From c07c56f89bfeafdf2c52667ff14a99d9d7ee621b Mon Sep 17 00:00:00 2001 From: Vincent Salucci Date: Thu, 20 Aug 2020 21:32:20 -0500 Subject: [PATCH 1/7] Initial commit of set password flow --- scripts/notarize.js | 1 + src/app/accounts/set-password.component.html | 105 +++++++++++++++++++ src/app/accounts/set-password.component.ts | 68 ++++++++++++ src/app/app-routing.module.ts | 2 + src/app/app.module.ts | 2 + 5 files changed, 178 insertions(+) create mode 100644 src/app/accounts/set-password.component.html create mode 100644 src/app/accounts/set-password.component.ts diff --git a/scripts/notarize.js b/scripts/notarize.js index 9336dd31..e7be1ace 100644 --- a/scripts/notarize.js +++ b/scripts/notarize.js @@ -2,6 +2,7 @@ require('dotenv').config(); const { notarize } = require('electron-notarize'); exports.default = async function notarizing(context) { + return; const { electronPlatformName, appOutDir } = context; if (electronPlatformName !== 'darwin') { return; diff --git a/src/app/accounts/set-password.component.html b/src/app/accounts/set-password.component.html new file mode 100644 index 00000000..ccae85a8 --- /dev/null +++ b/src/app/accounts/set-password.component.html @@ -0,0 +1,105 @@ +
+
+ Bitwarden +

{{'setMasterPassword' | i18n}}

+
+ {{'ssoCompleteRegistration' | i18n}} + + {{'masterPasswordPolicyInEffect' | i18n}} +
    +
  • + {{'policyInEffectMinComplexity' | i18n : getPasswordScoreAlertDisplay()}} +
  • +
  • + {{'policyInEffectMinLength' | i18n : enforcedPolicyOptions?.minLength.toString()}} +
  • +
  • {{'policyInEffectUppercase' | i18n}}
  • +
  • {{'policyInEffectLowercase' | i18n}}
  • +
  • {{'policyInEffectNumbers' | i18n}}
  • +
  • {{'policyInEffectSpecial' | i18n : '!@#$%^&*'}} +
  • +
+
+
+ +
+
+
+
+
+ + +
+
+ + + +
+
+
+
+
+
+
+
+ +
+
+
+
+
+
+ + +
+
+ + + +
+
+
+
+
+
+
+
+ + +
+
+ +
+
+ + +
+ +
+ diff --git a/src/app/accounts/set-password.component.ts b/src/app/accounts/set-password.component.ts new file mode 100644 index 00000000..cd3e9e85 --- /dev/null +++ b/src/app/accounts/set-password.component.ts @@ -0,0 +1,68 @@ +import { Component } from '@angular/core'; + +import { + ActivatedRoute, + Router, +} from '@angular/router'; + +import { ApiService } from 'jslib/abstractions/api.service'; +import { CipherService } from 'jslib/abstractions/cipher.service'; +import { CryptoService } from 'jslib/abstractions/crypto.service'; +import { FolderService } from 'jslib/abstractions/folder.service'; +import { I18nService } from 'jslib/abstractions/i18n.service'; +import { MessagingService } from 'jslib/abstractions/messaging.service'; +import { PasswordGenerationService } from 'jslib/abstractions/passwordGeneration.service'; +import { PlatformUtilsService } from 'jslib/abstractions/platformUtils.service'; +import { PolicyService } from 'jslib/abstractions/policy.service'; +import { SyncService } from 'jslib/abstractions/sync.service'; +import { UserService } from 'jslib/abstractions/user.service'; + +import { + SetPasswordComponent as BaseSetPasswordComponent, +} from 'jslib/angular/components/set-password.component'; + +@Component({ + selector: 'app-set-password', + templateUrl: 'set-password.component.html', +}) +export class SetPasswordComponent extends BaseSetPasswordComponent { + constructor(apiService: ApiService, i18nService: I18nService, + cryptoService: CryptoService, messagingService: MessagingService, + userService: UserService, passwordGenerationService: PasswordGenerationService, + platformUtilsService: PlatformUtilsService, folderService: FolderService, + cipherService: CipherService, syncService: SyncService, + policyService: PolicyService, router: Router, route: ActivatedRoute) { + super(apiService, i18nService, cryptoService, messagingService, userService, passwordGenerationService, + platformUtilsService, folderService, cipherService, syncService, policyService, router, route); + } + + get masterPasswordScoreWidth() { + return this.masterPasswordScore == null ? 0 : (this.masterPasswordScore + 1) * 20; + } + + get masterPasswordScoreColor() { + switch (this.masterPasswordScore) { + case 4: + return 'success'; + case 3: + return 'primary'; + case 2: + return 'warning'; + default: + return 'danger'; + } + } + + get masterPasswordScoreText() { + switch (this.masterPasswordScore) { + case 4: + return this.i18nService.t('strong'); + case 3: + return this.i18nService.t('good'); + case 2: + return this.i18nService.t('weak'); + default: + return this.masterPasswordScore != null ? this.i18nService.t('weak') : null; + } + } +} diff --git a/src/app/app-routing.module.ts b/src/app/app-routing.module.ts index 82fda652..b8b6ae52 100644 --- a/src/app/app-routing.module.ts +++ b/src/app/app-routing.module.ts @@ -8,6 +8,7 @@ import { AuthGuardService } from './services/auth-guard.service'; import { LaunchGuardService } from './services/launch-guard.service'; import { LoginComponent } from './accounts/login.component'; +import { SetPasswordComponent } from './accounts/set-password.component'; import { SsoComponent } from './accounts/sso.component'; import { TwoFactorComponent } from './accounts/two-factor.component'; import { DashboardComponent } from './tabs/dashboard.component'; @@ -24,6 +25,7 @@ const routes: Routes = [ }, { path: '2fa', component: TwoFactorComponent }, { path: 'sso', component: SsoComponent }, + { path: 'set-password', component: SetPasswordComponent }, { path: 'tabs', component: TabsComponent, diff --git a/src/app/app.module.ts b/src/app/app.module.ts index 30fccc20..1f2f2ece 100644 --- a/src/app/app.module.ts +++ b/src/app/app.module.ts @@ -26,6 +26,7 @@ import { TwoFactorOptionsComponent } from './accounts/two-factor-options.compone import { TwoFactorComponent } from './accounts/two-factor.component'; import { DashboardComponent } from './tabs/dashboard.component'; import { MoreComponent } from './tabs/more.component'; +import { SetPasswordComponent } from './accounts/set-password.component'; import { SettingsComponent } from './tabs/settings.component'; import { TabsComponent } from './tabs/tabs.component'; @@ -72,6 +73,7 @@ import { SearchCiphersPipe } from 'jslib/angular/pipes/search-ciphers.pipe'; ModalComponent, MoreComponent, SearchCiphersPipe, + SetPasswordComponent, SettingsComponent, SsoComponent, StopClickDirective, From 6650b4848d07b20db2c7344bec3d4870c5008b1d Mon Sep 17 00:00:00 2001 From: Vincent Salucci Date: Fri, 21 Aug 2020 09:24:09 -0500 Subject: [PATCH 2/7] Initial commit for bootstrap styled set-password --- src/app/accounts/set-password.component.html | 156 ++++++++----------- 1 file changed, 66 insertions(+), 90 deletions(-) diff --git a/src/app/accounts/set-password.component.html b/src/app/accounts/set-password.component.html index ccae85a8..42d3484c 100644 --- a/src/app/accounts/set-password.component.html +++ b/src/app/accounts/set-password.component.html @@ -1,105 +1,81 @@ -
-
- Bitwarden -

{{'setMasterPassword' | i18n}}

-
- {{'ssoCompleteRegistration' | i18n}} - - {{'masterPasswordPolicyInEffect' | i18n}} -
    -
  • - {{'policyInEffectMinComplexity' | i18n : getPasswordScoreAlertDisplay()}} -
  • -
  • - {{'policyInEffectMinLength' | i18n : enforcedPolicyOptions?.minLength.toString()}} -
  • -
  • {{'policyInEffectUppercase' | i18n}}
  • -
  • {{'policyInEffectLowercase' | i18n}}
  • -
  • {{'policyInEffectNumbers' | i18n}}
  • -
  • {{'policyInEffectSpecial' | i18n : '!@#$%^&*'}} -
  • -
-
-
- -
-
-
-
-
- + +
+
+

{{'setMasterPassword' | i18n}}

+
+
+ {{'ssoCompleteRegistration' | i18n}} +
+ + {{'masterPasswordPolicyInEffect' | i18n}} +
    +
  • + {{'policyInEffectMinComplexity' | i18n : getPasswordScoreAlertDisplay()}} +
  • +
  • + {{'policyInEffectMinLength' | i18n : enforcedPolicyOptions?.minLength.toString()}} +
  • +
  • + {{'policyInEffectUppercase' | i18n}}
  • +
  • + {{'policyInEffectLowercase' | i18n}}
  • +
  • + {{'policyInEffectNumbers' | i18n}}
  • +
  • + {{'policyInEffectSpecial' | i18n : '!@#$%^&*'}}
  • +
+
+ +
+
+ name="MasterPasswordHash" class="text-monospace form-control mb-1" + [(ngModel)]="masterPassword" (input)="updatePasswordStrength()" required + appInputVerbatim> + +
-
- + +
-
-
-
+ {{'masterPassDesc' | i18n}} +
+
+ +
+ +
-
- -
-
-
-
-
-
- - -
-
- - - -
-
-
-
-
-
-
-
+
- + + {{'masterPassHintDesc' | i18n}} +
+
+
+ +
-
-
- - -
- +
From c6216778520b63ec2901f6f5a3aee5c90b81c109 Mon Sep 17 00:00:00 2001 From: Vincent Salucci Date: Sat, 22 Aug 2020 08:06:08 -0500 Subject: [PATCH 3/7] update jslib (5d874d0 -> 6ab444a) --- jslib | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/jslib b/jslib index 5d874d07..6ab444a9 160000 --- a/jslib +++ b/jslib @@ -1 +1 @@ -Subproject commit 5d874d07b35a23dc6d54f1f435d88d2ddd815e33 +Subproject commit 6ab444a9868c32ac53761f9d233d816744da9a1d From 626892473f090e3475f5664406cc8fb49306989d Mon Sep 17 00:00:00 2001 From: Vincent Salucci Date: Sat, 22 Aug 2020 12:47:50 -0500 Subject: [PATCH 4/7] Updated dependency chain // Updated UI // Added Policy Service // Added missing strings // Added callout styles --- src/app/accounts/set-password.component.html | 143 ++++++++++--------- src/app/accounts/set-password.component.ts | 16 +-- src/app/services/services.module.ts | 6 +- src/locales/en/messages.json | 63 ++++++++ src/scss/misc.scss | 65 +++++++++ 5 files changed, 213 insertions(+), 80 deletions(-) diff --git a/src/app/accounts/set-password.component.html b/src/app/accounts/set-password.component.html index 42d3484c..27cc4283 100644 --- a/src/app/accounts/set-password.component.html +++ b/src/app/accounts/set-password.component.html @@ -1,81 +1,90 @@ -
-
-
-

{{'setMasterPassword' | i18n}}

-
-
- {{'ssoCompleteRegistration' | i18n}} -
- - {{'masterPasswordPolicyInEffect' | i18n}} -
    -
  • - {{'policyInEffectMinComplexity' | i18n : getPasswordScoreAlertDisplay()}} -
  • -
  • - {{'policyInEffectMinLength' | i18n : enforcedPolicyOptions?.minLength.toString()}} -
  • -
  • - {{'policyInEffectUppercase' | i18n}}
  • -
  • - {{'policyInEffectLowercase' | i18n}}
  • -
  • - {{'policyInEffectNumbers' | i18n}}
  • -
  • - {{'policyInEffectSpecial' | i18n : '!@#$%^&*'}}
  • -
-
- -
-
- - - +
+ +
+
+
+
{{'setMasterPassword' | i18n}}
+
+ {{'ssoCompleteRegistration' | i18n}} +
+ + {{'masterPasswordPolicyInEffect' | i18n}} +
    +
  • + {{'policyInEffectMinComplexity' | i18n : getPasswordScoreAlertDisplay()}} +
  • +
  • + {{'policyInEffectMinLength' | i18n : enforcedPolicyOptions?.minLength.toString()}} +
  • +
  • + {{'policyInEffectUppercase' | i18n}}
  • +
  • + {{'policyInEffectLowercase' | i18n}}
  • +
  • + {{'policyInEffectNumbers' | i18n}}
  • +
  • + {{'policyInEffectSpecial' | i18n : '!@#$%^&*'}}
  • +
+
+ +
+
+ +
+
+
+
+
+
+ + +
-
+ {{'masterPassDesc' | i18n}} +
+
+ +
+ -
- {{'masterPassDesc' | i18n}} -
-
- +
+ + + {{'masterPassHintDesc' | i18n}} +
+
- - +
-
- - - {{'masterPassHintDesc' | i18n}} -
-
-
- - -
-
- + +
diff --git a/src/app/accounts/set-password.component.ts b/src/app/accounts/set-password.component.ts index cd3e9e85..a36e7d04 100644 --- a/src/app/accounts/set-password.component.ts +++ b/src/app/accounts/set-password.component.ts @@ -1,20 +1,14 @@ import { Component } from '@angular/core'; -import { - ActivatedRoute, - Router, -} from '@angular/router'; +import { Router } from '@angular/router'; import { ApiService } from 'jslib/abstractions/api.service'; -import { CipherService } from 'jslib/abstractions/cipher.service'; import { CryptoService } from 'jslib/abstractions/crypto.service'; -import { FolderService } from 'jslib/abstractions/folder.service'; import { I18nService } from 'jslib/abstractions/i18n.service'; import { MessagingService } from 'jslib/abstractions/messaging.service'; import { PasswordGenerationService } from 'jslib/abstractions/passwordGeneration.service'; import { PlatformUtilsService } from 'jslib/abstractions/platformUtils.service'; import { PolicyService } from 'jslib/abstractions/policy.service'; -import { SyncService } from 'jslib/abstractions/sync.service'; import { UserService } from 'jslib/abstractions/user.service'; import { @@ -29,11 +23,9 @@ export class SetPasswordComponent extends BaseSetPasswordComponent { constructor(apiService: ApiService, i18nService: I18nService, cryptoService: CryptoService, messagingService: MessagingService, userService: UserService, passwordGenerationService: PasswordGenerationService, - platformUtilsService: PlatformUtilsService, folderService: FolderService, - cipherService: CipherService, syncService: SyncService, - policyService: PolicyService, router: Router, route: ActivatedRoute) { - super(apiService, i18nService, cryptoService, messagingService, userService, passwordGenerationService, - platformUtilsService, folderService, cipherService, syncService, policyService, router, route); + platformUtilsService: PlatformUtilsService, policyService: PolicyService, router: Router) { + super(i18nService, cryptoService, messagingService, userService, passwordGenerationService, + platformUtilsService, policyService, router, apiService); } get masterPasswordScoreWidth() { diff --git a/src/app/services/services.module.ts b/src/app/services/services.module.ts index 4cb71e28..478818f4 100644 --- a/src/app/services/services.module.ts +++ b/src/app/services/services.module.ts @@ -34,6 +34,7 @@ import { CryptoService } from 'jslib/services/crypto.service'; import { EnvironmentService } from 'jslib/services/environment.service'; import { NodeCryptoFunctionService } from 'jslib/services/nodeCryptoFunction.service'; import { PasswordGenerationService } from 'jslib/services/passwordGeneration.service'; +import { PolicyService } from 'jslib/services/policy.service'; import { StateService } from 'jslib/services/state.service'; import { TokenService } from 'jslib/services/token.service'; import { UserService } from 'jslib/services/user.service'; @@ -51,6 +52,7 @@ import { PasswordGenerationService as PasswordGenerationServiceAbstraction, } from 'jslib/abstractions/passwordGeneration.service'; import { PlatformUtilsService as PlatformUtilsServiceAbstraction } from 'jslib/abstractions/platformUtils.service'; +import { PolicyService as PolicyServiceAbstraction } from 'jslib/abstractions/policy.service'; import { StateService as StateServiceAbstraction } from 'jslib/abstractions/state.service'; import { StorageService as StorageServiceAbstraction } from 'jslib/abstractions/storage.service'; import { TokenService as TokenServiceAbstraction } from 'jslib/abstractions/token.service'; @@ -79,6 +81,7 @@ const configurationService = new ConfigurationService(storageService, secureStor const syncService = new SyncService(configurationService, logService, cryptoFunctionService, apiService, messagingService, i18nService); const passwordGenerationService = new PasswordGenerationService(cryptoService, storageService, null); +const policyService = new PolicyService(userService, storageService); const analytics = new Analytics(window, () => true, platformUtilsService, storageService, appIdService); containerService.attachToWindow(window); @@ -140,7 +143,8 @@ export function initFactory(): Function { { provide: ConfigurationService, useValue: configurationService }, { provide: SyncService, useValue: syncService }, { provide: PasswordGenerationServiceAbstraction, useValue: passwordGenerationService }, - { provide: CryptoFunctionServiceAbstraction, useValue: cryptoFunctionService }, + { provide: CryptoFunctionServiceAbstraction, useValue: cryptoFunctionService }, , + { provide: PolicyServiceAbstraction, useValue: policyService }, { provide: APP_INITIALIZER, useFactory: initFactory, diff --git a/src/locales/en/messages.json b/src/locales/en/messages.json index e4134a76..584110f0 100644 --- a/src/locales/en/messages.json +++ b/src/locales/en/messages.json @@ -617,5 +617,68 @@ }, "enterpriseSingleSignOn": { "message": "Enterprise Single Sign-On" + }, + "setMasterPassword": { + "message": "Set Master Password" + }, + "ssoCompleteRegistration": { + "message": "In order to complete logging in with SSO, please set a master password to access and protect your vault." + }, + "newMasterPass": { + "message": "New Master Password" + }, + "confirmNewMasterPass": { + "message": "Confirm New Master Password" + }, + "masterPasswordPolicyInEffect": { + "message": "One or more organization policies require your master password to meet the following requirements:" + }, + "policyInEffectMinComplexity": { + "message": "Minimum complexity score of $SCORE$", + "placeholders": { + "score": { + "content": "$1", + "example": "4" + } + } + }, + "policyInEffectMinLength": { + "message": "Minimum length of $LENGTH$", + "placeholders": { + "length": { + "content": "$1", + "example": "14" + } + } + }, + "policyInEffectUppercase": { + "message": "Contain one or more uppercase characters" + }, + "policyInEffectLowercase": { + "message": "Contain one or more lowercase characters" + }, + "policyInEffectNumbers": { + "message": "Contain one or more numbers" + }, + "policyInEffectSpecial": { + "message": "Contain one or more of the following special characters $CHARS$", + "placeholders": { + "chars": { + "content": "$1", + "example": "!@#$%^&*" + } + } + }, + "masterPassDesc": { + "message": "The master password is the password you use to access your vault. It is very important that you do not forget your master password. There is no way to recover the password in the event that you forget it." + }, + "reTypeMasterPass": { + "message": "Re-type Master Password" + }, + "masterPassHint": { + "message": "Master Password Hint (optional)" + }, + "masterPassHintDesc": { + "message": "A master password hint can help you remember your password if you forget it." } } diff --git a/src/scss/misc.scss b/src/scss/misc.scss index ab58ca2f..b093fe97 100644 --- a/src/scss/misc.scss +++ b/src/scss/misc.scss @@ -53,3 +53,68 @@ ul.testing-list { text-decoration: line-through; } } + +.callout { + padding: 10px; + margin-bottom: 10px; + border: 1px solid #000000; + border-left-width: 5px; + border-radius: 3px; + border-color: #ddd; + background-color: white; + + .callout-heading { + margin-top: 0; + } + + h3.callout-heading { + font-weight: bold; + text-transform: uppercase; + } + + &.callout-primary { + border-left-color: $primary; + + .callout-heading { + color: $primary; + } + } + + &.callout-info { + border-left-color: $info; + + .callout-heading { + color: $info; + } + } + + &.callout-danger { + border-left-color: $danger; + + .callout-heading { + color: $danger; + } + } + + &.callout-success { + border-left-color: $success; + + .callout-heading { + color: $success; + } + } + + &.callout-warning { + border-left-color: $warning; + + .callout-heading { + color: $warning; + } + } + + ul { + padding-left: 40px; + margin: 0; + } +} + From ab37221182650f6eff573cbc1b9e92152ad04e9a Mon Sep 17 00:00:00 2001 From: Vincent Salucci Date: Sat, 22 Aug 2020 14:28:22 -0500 Subject: [PATCH 5/7] Updated UI for password strength // Updated success route // Add more missing strings --- src/app/accounts/set-password.component.html | 22 +++++++----- src/app/accounts/set-password.component.ts | 1 + src/locales/en/messages.json | 36 ++++++++++++++++++++ 3 files changed, 51 insertions(+), 8 deletions(-) diff --git a/src/app/accounts/set-password.component.html b/src/app/accounts/set-password.component.html index 27cc4283..35835493 100644 --- a/src/app/accounts/set-password.component.html +++ b/src/app/accounts/set-password.component.html @@ -7,7 +7,7 @@
{{'ssoCompleteRegistration' | i18n}}
- + {{'masterPasswordPolicyInEffect' | i18n}}
  • @@ -16,17 +16,22 @@
  • {{'policyInEffectMinLength' | i18n : enforcedPolicyOptions?.minLength.toString()}}
  • -
  • +
  • {{'policyInEffectUppercase' | i18n}}
  • -
  • +
  • {{'policyInEffectLowercase' | i18n}}
  • -
  • +
  • {{'policyInEffectNumbers' | i18n}}
  • -
  • +
  • {{'policyInEffectSpecial' | i18n : '!@#$%^&*'}}
- +