1
0
mirror of https://github.com/bitwarden/browser synced 2025-12-15 07:43:35 +00:00

[Reset Password v1] Update Temp Password

This commit is contained in:
Vincent Salucci
2021-08-05 09:56:17 -05:00
parent 090e9f35ae
commit 2bddc1017b
9 changed files with 187 additions and 5 deletions

View File

@@ -1752,5 +1752,14 @@
}, },
"emailVerificationRequiredDesc": { "emailVerificationRequiredDesc": {
"message": "You must verify your email to use this feature. You can verify your email in the web vault." "message": "You must verify your email to use this feature. You can verify your email in the web vault."
},
"updatedMasterPassword": {
"message": "Updated Master Password"
},
"updateMasterPassword": {
"message": "Update Master Password"
},
"updateMasterPasswordWarning": {
"message": "Your Master Password was recently changed by an administrator in your organization. In order to access the vault, you must update it now. Proceeding will log you out of your current session, requiring you to log back in. Active sessions on other devices may continue to remain active for up to one hour."
} }
} }

View File

@@ -10,6 +10,7 @@ import { PlatformUtilsService } from 'jslib-common/abstractions/platformUtils.se
import { StateService } from 'jslib-common/abstractions/state.service'; import { StateService } from 'jslib-common/abstractions/state.service';
import { StorageService } from 'jslib-common/abstractions/storage.service'; import { StorageService } from 'jslib-common/abstractions/storage.service';
import { SyncService } from 'jslib-common/abstractions/sync.service'; import { SyncService } from 'jslib-common/abstractions/sync.service';
import { UserService } from 'jslib-common/abstractions/user.service';
import { LoginComponent as BaseLoginComponent } from 'jslib-angular/components/login.component'; import { LoginComponent as BaseLoginComponent } from 'jslib-angular/components/login.component';
@@ -23,12 +24,19 @@ export class LoginComponent extends BaseLoginComponent {
protected stateService: StateService, protected environmentService: EnvironmentService, protected stateService: StateService, protected environmentService: EnvironmentService,
protected passwordGenerationService: PasswordGenerationService, protected passwordGenerationService: PasswordGenerationService,
protected cryptoFunctionService: CryptoFunctionService, storageService: StorageService, protected cryptoFunctionService: CryptoFunctionService, storageService: StorageService,
syncService: SyncService) { syncService: SyncService, private userService: UserService) {
super(authService, router, platformUtilsService, i18nService, stateService, environmentService, passwordGenerationService, cryptoFunctionService, storageService); super(authService, router, platformUtilsService, i18nService, stateService, environmentService, passwordGenerationService, cryptoFunctionService, storageService);
super.onSuccessfulLogin = () => { super.onSuccessfulLogin = () => {
return syncService.fullSync(true); return syncService.fullSync(true);
}; };
super.successRoute = '/tabs/vault'; super.successRoute = '/tabs/vault';
super.onSuccessfulLoginNavigate = async () => {
if (await this.userService.getForcePasswordReset()) {
this.router.navigate(['update-temp-password']);
} else {
this.router.navigate([this.successRoute]);
}
};
} }
settings() { settings() {

View File

@@ -31,6 +31,13 @@ export class SetPasswordComponent extends BaseSetPasswordComponent {
syncService: SyncService, route: ActivatedRoute) { syncService: SyncService, route: ActivatedRoute) {
super(i18nService, cryptoService, messagingService, userService, passwordGenerationService, super(i18nService, cryptoService, messagingService, userService, passwordGenerationService,
platformUtilsService, policyService, router, apiService, syncService, route); platformUtilsService, policyService, router, apiService, syncService, route);
super.onSuccessfulChangePassword = async () => {
if (await this.userService.getForcePasswordReset()) {
this.router.navigate(['update-temp-password']);
} else {
this.router.navigate([this.successRoute]);
}
};
} }
get masterPasswordScoreWidth() { get masterPasswordScoreWidth() {

View File

@@ -15,6 +15,7 @@ import { PlatformUtilsService } from 'jslib-common/abstractions/platformUtils.se
import { StateService } from 'jslib-common/abstractions/state.service'; import { StateService } from 'jslib-common/abstractions/state.service';
import { StorageService } from 'jslib-common/abstractions/storage.service'; import { StorageService } from 'jslib-common/abstractions/storage.service';
import { SyncService } from 'jslib-common/abstractions/sync.service'; import { SyncService } from 'jslib-common/abstractions/sync.service';
import { UserService } from 'jslib-common/abstractions/user.service';
import { SsoComponent as BaseSsoComponent } from 'jslib-angular/components/sso.component'; import { SsoComponent as BaseSsoComponent } from 'jslib-angular/components/sso.component';
import { BrowserApi } from '../../browser/browserApi'; import { BrowserApi } from '../../browser/browserApi';
@@ -29,7 +30,7 @@ export class SsoComponent extends BaseSsoComponent {
storageService: StorageService, stateService: StateService, storageService: StorageService, stateService: StateService,
platformUtilsService: PlatformUtilsService, apiService: ApiService, platformUtilsService: PlatformUtilsService, apiService: ApiService,
cryptoFunctionService: CryptoFunctionService, passwordGenerationService: PasswordGenerationService, cryptoFunctionService: CryptoFunctionService, passwordGenerationService: PasswordGenerationService,
syncService: SyncService, environmentService: EnvironmentService) { syncService: SyncService, environmentService: EnvironmentService, private userService: UserService) {
super(authService, router, i18nService, route, storageService, stateService, platformUtilsService, super(authService, router, i18nService, route, storageService, stateService, platformUtilsService,
apiService, cryptoFunctionService, environmentService, passwordGenerationService); apiService, cryptoFunctionService, environmentService, passwordGenerationService);
@@ -44,5 +45,13 @@ export class SsoComponent extends BaseSsoComponent {
const thisWindow = window.open('', '_self'); const thisWindow = window.open('', '_self');
thisWindow.close(); thisWindow.close();
}; };
super.onSuccessfulLoginNavigate = async () => {
if (await this.userService.getForcePasswordReset()) {
this.router.navigate(['update-temp-password']);
} else {
this.router.navigate([this.successRoute]);
}
};
} }
} }

View File

@@ -20,6 +20,7 @@ import { PlatformUtilsService } from 'jslib-common/abstractions/platformUtils.se
import { StateService } from 'jslib-common/abstractions/state.service'; import { StateService } from 'jslib-common/abstractions/state.service';
import { StorageService } from 'jslib-common/abstractions/storage.service'; import { StorageService } from 'jslib-common/abstractions/storage.service';
import { SyncService } from 'jslib-common/abstractions/sync.service'; import { SyncService } from 'jslib-common/abstractions/sync.service';
import { UserService } from 'jslib-common/abstractions/user.service';
import { BroadcasterService } from 'jslib-angular/services/broadcaster.service'; import { BroadcasterService } from 'jslib-angular/services/broadcaster.service';
@@ -44,7 +45,8 @@ export class TwoFactorComponent extends BaseTwoFactorComponent {
environmentService: EnvironmentService, private ngZone: NgZone, environmentService: EnvironmentService, private ngZone: NgZone,
private broadcasterService: BroadcasterService, private changeDetectorRef: ChangeDetectorRef, private broadcasterService: BroadcasterService, private changeDetectorRef: ChangeDetectorRef,
private popupUtilsService: PopupUtilsService, stateService: StateService, private popupUtilsService: PopupUtilsService, stateService: StateService,
storageService: StorageService, route: ActivatedRoute, private messagingService: MessagingService) { storageService: StorageService, route: ActivatedRoute, private messagingService: MessagingService,
private userService: UserService) {
super(authService, router, i18nService, apiService, platformUtilsService, window, environmentService, super(authService, router, i18nService, apiService, platformUtilsService, window, environmentService,
stateService, storageService, route); stateService, storageService, route);
super.onSuccessfulLogin = () => { super.onSuccessfulLogin = () => {
@@ -52,6 +54,17 @@ export class TwoFactorComponent extends BaseTwoFactorComponent {
}; };
super.successRoute = '/tabs/vault'; super.successRoute = '/tabs/vault';
this.webAuthnNewTab = this.platformUtilsService.isFirefox() || this.platformUtilsService.isSafari(); this.webAuthnNewTab = this.platformUtilsService.isFirefox() || this.platformUtilsService.isSafari();
super.onSuccessfulLoginNavigate = async () => {
if (await this.userService.getForcePasswordReset()) {
this.router.navigate(['update-temp-password']);
} else {
this.router.navigate([this.successRoute], {
queryParams: {
identifier: this.identifier,
},
});
}
}
} }
async ngOnInit() { async ngOnInit() {

View File

@@ -0,0 +1,100 @@
<form #form (ngSubmit)="submit()" [appApiAction]="formPromise">
<header>
<div class="left">
<a (click)="logOut()">{{'logOut' | i18n}}</a>
</div>
<div class="center">
<span class="title">{{'updateMasterPassword' | i18n}}</span>
</div>
<div class="right">
<button type="submit" appBlurClick [disabled]="form.loading">
<span [hidden]="form.loading">{{'submit' | i18n}}</span>
<i class="fa fa-spinner fa-lg fa-spin" [hidden]="!form.loading" aria-hidden="true"></i>
</button>
</div>
</header>
<content>
<app-callout type="warning" title="{{'updateMasterPasswordWarning' | i18n}}">
{{'updateMasterPasswordWarning' | i18n}}
</app-callout>
<app-callout type="info" *ngIf="enforcedPolicyOptions">
{{'masterPasswordPolicyInEffect' | i18n}}
<ul>
<li *ngIf="enforcedPolicyOptions?.minComplexity > 0">
{{'policyInEffectMinComplexity' | i18n : getPasswordScoreAlertDisplay()}}
</li>
<li *ngIf="enforcedPolicyOptions?.minLength > 0">
{{'policyInEffectMinLength' | i18n : enforcedPolicyOptions?.minLength.toString()}}
</li>
<li *ngIf="enforcedPolicyOptions?.requireUpper">{{'policyInEffectUppercase' | i18n}}</li>
<li *ngIf="enforcedPolicyOptions?.requireLower">{{'policyInEffectLowercase' | i18n}}</li>
<li *ngIf="enforcedPolicyOptions?.requireNumbers">{{'policyInEffectNumbers' | i18n}}</li>
<li *ngIf="enforcedPolicyOptions?.requireSpecial">
{{'policyInEffectSpecial' | i18n : '!@#$%^&*'}}
</li>
</ul>
</app-callout>
<div class="box">
<div class="box-content">
<div class="box-content-row" appBoxRow>
<div class="box-content-row-flex">
<div class="row-main">
<label for="masterPassword">
{{'masterPass' | i18n}}
<strong class="sub-label text-{{masterPasswordScoreColor}}"
*ngIf="masterPasswordScoreText">
{{masterPasswordScoreText}}
</strong>
</label>
<input id="masterPassword" type="{{showPassword ? 'text' : 'password'}}"
name="MasterPassword" class="monospaced" [(ngModel)]="masterPassword" required
[appAutofocus]="email !== ''" appInputVerbatim (input)="updatePasswordStrength()">
</div>
<div class="action-buttons">
<a class="row-btn" href="#" appStopClick appBlurClick
appA11yTitle="{{'toggleVisibility' | i18n}}" (click)="togglePassword(false)">
<i class="fa fa-lg" aria-hidden="true"
[ngClass]="{'fa-eye': !showPassword, 'fa-eye-slash': showPassword}"></i>
</a>
</div>
</div>
<div class="progress">
<div class="progress-bar bg-{{masterPasswordScoreColor}}" role="progressbar" aria-valuenow="0"
aria-valuemin="0" aria-valuemax="100" [ngStyle]="{width: (masterPasswordScoreWidth + '%')}"
attr.aria-valuenow="{{masterPasswordScoreWidth}}"></div>
</div>
</div>
</div>
</div>
<div class="box">
<div class="box-content">
<div class="box-content-row box-content-row-flex" appBoxRow>
<div class="row-main">
<label for="masterPasswordRetype">{{'reTypeMasterPass' | i18n}}</label>
<input id="masterPasswordRetype" type="{{showPassword ? 'text' : 'password'}}"
name="MasterPasswordRetype" class="monospaced" [(ngModel)]="confirmMasterPassword" required
appInputVerbatim>
</div>
<div class="action-buttons">
<a class="row-btn" href="#" appStopClick appBlurClick
appA11yTitle="{{'toggleVisibility' | i18n}}" (click)="togglePassword(true)">
<i class="fa fa-lg" aria-hidden="true"
[ngClass]="{'fa-eye': !showPassword, 'fa-eye-slash': showPassword}"></i>
</a>
</div>
</div>
</div>
</div>
<div class="box">
<div class="box-content">
<div class="box-content-row" appBoxRow>
<label for="hint">{{'masterPassHint' | i18n}}</label>
<input id="hint" type="text" name="Hint" [(ngModel)]="hint">
</div>
</div>
<div class="box-footer">
{{'masterPassHintDesc' | i18n}}
</div>
</div>
</content>
</form>

View File

@@ -0,0 +1,27 @@
import { Component } from '@angular/core';
import { ApiService } from 'jslib-common/abstractions/api.service';
import { CryptoService } from 'jslib-common/abstractions/crypto.service';
import { I18nService } from 'jslib-common/abstractions/i18n.service';
import { MessagingService } from 'jslib-common/abstractions/messaging.service';
import { PasswordGenerationService } from 'jslib-common/abstractions/passwordGeneration.service';
import { PlatformUtilsService } from 'jslib-common/abstractions/platformUtils.service';
import { PolicyService } from 'jslib-common/abstractions/policy.service';
import { UserService } from 'jslib-common/abstractions/user.service';
import { UpdateTempPasswordComponent as BaseUpdateTempPasswordComponent } from 'jslib-angular/components/update-temp-password.component';
@Component({
selector: 'app-update-temp-password',
templateUrl: 'update-temp-password.component.html',
})
export class UpdateTempPasswordComponent extends BaseUpdateTempPasswordComponent {
constructor(i18nService: I18nService, platformUtilsService: PlatformUtilsService,
passwordGenerationService: PasswordGenerationService, policyService: PolicyService,
cryptoService: CryptoService, userService: UserService,
messagingService: MessagingService, apiService: ApiService) {
super(i18nService, platformUtilsService, passwordGenerationService, policyService, cryptoService,
userService, messagingService, apiService);
}
}

View File

@@ -22,6 +22,7 @@ import { SetPasswordComponent } from './accounts/set-password.component';
import { SsoComponent } from './accounts/sso.component'; import { SsoComponent } from './accounts/sso.component';
import { TwoFactorOptionsComponent } from './accounts/two-factor-options.component'; import { TwoFactorOptionsComponent } from './accounts/two-factor-options.component';
import { TwoFactorComponent } from './accounts/two-factor.component'; import { TwoFactorComponent } from './accounts/two-factor.component';
import { UpdateTempPasswordComponent } from './accounts/update-temp-password.component';
import { PasswordGeneratorHistoryComponent } from './generator/password-generator-history.component'; import { PasswordGeneratorHistoryComponent } from './generator/password-generator-history.component';
import { PasswordGeneratorComponent } from './generator/password-generator.component'; import { PasswordGeneratorComponent } from './generator/password-generator.component';
@@ -261,6 +262,12 @@ const routes: Routes = [
canActivate: [AuthGuardService], canActivate: [AuthGuardService],
data: { state: 'edit-send' }, data: { state: 'edit-send' },
}, },
{
path: 'update-temp-password',
component: UpdateTempPasswordComponent,
canActivate: [AuthGuardService],
data: { state: 'update-temp-password' },
},
{ {
path: 'tabs', path: 'tabs',
component: TabsComponent, component: TabsComponent,

View File

@@ -20,6 +20,7 @@ import { SetPasswordComponent } from './accounts/set-password.component';
import { SsoComponent } from './accounts/sso.component'; import { SsoComponent } from './accounts/sso.component';
import { TwoFactorOptionsComponent } from './accounts/two-factor-options.component'; import { TwoFactorOptionsComponent } from './accounts/two-factor-options.component';
import { TwoFactorComponent } from './accounts/two-factor.component'; import { TwoFactorComponent } from './accounts/two-factor.component';
import { UpdateTempPasswordComponent } from './accounts/update-temp-password.component';
import { PasswordGeneratorHistoryComponent } from './generator/password-generator-history.component'; import { PasswordGeneratorHistoryComponent } from './generator/password-generator-history.component';
import { PasswordGeneratorComponent } from './generator/password-generator.component'; import { PasswordGeneratorComponent } from './generator/password-generator.component';
@@ -224,8 +225,10 @@ registerLocaleData(localeZhTw, 'zh-TW');
SendGroupingsComponent, SendGroupingsComponent,
SendListComponent, SendListComponent,
SendTypeComponent, SendTypeComponent,
SetPasswordComponent,
SettingsComponent, SettingsComponent,
ShareComponent, ShareComponent,
SsoComponent,
StopClickDirective, StopClickDirective,
StopPropDirective, StopPropDirective,
SyncComponent, SyncComponent,
@@ -233,9 +236,8 @@ registerLocaleData(localeZhTw, 'zh-TW');
TrueFalseValueDirective, TrueFalseValueDirective,
TwoFactorOptionsComponent, TwoFactorOptionsComponent,
TwoFactorComponent, TwoFactorComponent,
SsoComponent, UpdateTempPasswordComponent,
ViewComponent, ViewComponent,
SetPasswordComponent,
], ],
entryComponents: [], entryComponents: [],
providers: [ providers: [