1
0
mirror of https://github.com/bitwarden/browser.git synced 2024-12-25 16:59:17 +01:00

call api to set password with key parameters (#609)

* call api to set password with key parameters

* update ssoCompleteRegistration string
This commit is contained in:
Kyle Spearrin 2020-08-17 15:04:59 -04:00 committed by GitHub
parent 1fe7554818
commit e0ede7ba74
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 134 additions and 57 deletions

2
jslib

@ -1 +1 @@
Subproject commit ed6978baff5b129341bd46cc90a6155c1bcc5124
Subproject commit 7bf00b4fb37d85d8ffe7aa3248bd72f304297331

View File

@ -1,45 +1,81 @@
<div class="secondary-header">
<h1>{{'setMasterPassword' | i18n}}</h1>
</div>
<app-callout type="tip">{{'ssoCompleteRegistration' | i18n}}</app-callout>
<app-callout type="info" *ngIf="enforcedPolicyOptions">
{{'masterPasswordPolicyInEffect' | i18n}}
<ul class="mb-0">
<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>
<form #form (ngSubmit)="submit()" [appApiAction]="formPromise" ngNativeValidate autocomplete="off">
<div class="row">
<div class="col-6">
<div class="form-group">
<label for="newMasterPassword">{{'newMasterPass' | i18n}}</label>
<input id="newMasterPassword" type="password" name="NewMasterPasswordHash" class="form-control mb-1"
[(ngModel)]="newMasterPassword" (input)="updatePasswordStrength()" required appInputVerbatim
autocomplete="new-password">
<app-password-strength [score]="masterPasswordScore" [showText]="true"></app-password-strength>
</div>
</div>
<div class="col-6">
<div class="form-group">
<label for="confirmNewMasterPassword">{{'confirmNewMasterPass' | i18n}}</label>
<input id="confirmNewMasterPassword" type="password" name="ConfirmNewMasterPasswordHash"
class="form-control" [(ngModel)]="confirmNewMasterPassword" required appInputVerbatim
autocomplete="new-password">
<div class="row justify-content-md-center mt-5">
<div class="col-5">
<p class="lead text-center mb-4">{{'setMasterPassword' | i18n}}</p>
<div class="card d-block">
<div class="card-body">
<app-callout type="info">{{'ssoCompleteRegistration' | i18n}}</app-callout>
<div class="form-group">
<app-callout type="info" *ngIf="enforcedPolicyOptions">
{{'masterPasswordPolicyInEffect' | i18n}}
<ul class="mb-0">
<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>
<label for="masterPassword">{{'masterPass' | i18n}}</label>
<div class="d-flex">
<div class="w-100">
<input id="masterPassword" type="{{showPassword ? 'text' : 'password'}}"
name="MasterPasswordHash" class="text-monospace form-control mb-1"
[(ngModel)]="masterPassword" (input)="updatePasswordStrength()" required
appInputVerbatim>
<app-password-strength [score]="masterPasswordScore" [showText]="true">
</app-password-strength>
</div>
<div>
<button type="button" class="ml-1 btn btn-link"
appA11yTitle="{{'toggleVisibility' | i18n}}" (click)="togglePassword(false)">
<i class="fa fa-lg" aria-hidden="true"
[ngClass]="{'fa-eye': !showPassword, 'fa-eye-slash': showPassword}"></i>
</button>
<div class="progress-bar invisible"></div>
</div>
</div>
<small class="form-text text-muted">{{'masterPassDesc' | i18n}}</small>
</div>
<div class="form-group">
<label for="masterPasswordRetype">{{'reTypeMasterPass' | i18n}}</label>
<div class="d-flex">
<input id="masterPasswordRetype" type="{{showPassword ? 'text' : 'password'}}"
name="MasterPasswordRetype" class="text-monospace form-control"
[(ngModel)]="masterPasswordRetype" required appInputVerbatim>
<button type="button" class="ml-1 btn btn-link" appA11yTitle="{{'toggleVisibility' | i18n}}"
(click)="togglePassword(true)">
<i class="fa fa-lg" aria-hidden="true"
[ngClass]="{'fa-eye': !showPassword, 'fa-eye-slash': showPassword}"></i>
</button>
</div>
</div>
<div class="form-group">
<label for="hint">{{'masterPassHint' | i18n}}</label>
<input id="hint" class="form-control" type="text" name="Hint" [(ngModel)]="hint">
<small class="form-text text-muted">{{'masterPassHintDesc' | i18n}}</small>
</div>
<hr>
<div class="d-flex">
<button type="submit" class="btn btn-primary btn-block btn-submit" [disabled]="form.loading">
<i class="fa fa-spinner fa-spin" title="{{'loading' | i18n}}" aria-hidden="true"></i>
<span>{{'submit' | i18n}}</span>
</button>
<button type="button" class="btn btn-outline-secondary btn-block ml-2 mt-0" (click)="logOut()">
{{'logOut' | i18n}}
</button>
</div>
</div>
</div>
</div>
</div>
<button type="submit" class="btn btn-primary btn-submit" [disabled]="form.loading">
<i class="fa fa-spinner fa-spin" title="{{'loading' | i18n}}" aria-hidden="true"></i>
<span>{{'setMasterPassword' | i18n}}</span>
</button>
</form>

View File

@ -19,19 +19,25 @@ import { UserService } from 'jslib/abstractions/user.service';
import { CipherString } from 'jslib/models/domain/cipherString';
import { SymmetricCryptoKey } from 'jslib/models/domain/symmetricCryptoKey';
import { KeysRequest } from 'jslib/models/request/keysRequest';
import { SetPasswordRequest } from 'jslib/models/request/setPasswordRequest';
import {
ChangePasswordComponent as BaseChangePasswordComponent,
} from 'jslib/angular/components/change-password.component';
import { KdfType } from 'jslib/enums/kdfType';
@Component({
selector: 'app-accounts-change-password',
templateUrl: 'change-password.component.html',
})
export class ChangePasswordComponent extends BaseChangePasswordComponent {
showPassword: boolean = false;
hint: string = '';
onSuccessfulChangePassword: () => Promise<any>;
successRoute = 'lock';
successRoute = 'vault';
constructor(apiService: ApiService, i18nService: I18nService,
cryptoService: CryptoService, messagingService: MessagingService,
@ -43,16 +49,36 @@ export class ChangePasswordComponent extends BaseChangePasswordComponent {
platformUtilsService, folderService, cipherService, syncService, policyService, router);
}
async performSubmitActions(newMasterPasswordHash: string, newKey: SymmetricCryptoKey,
newEncKey: [SymmetricCryptoKey, CipherString]) {
const setRequest = new SetPasswordRequest();
setRequest.newMasterPasswordHash = newMasterPasswordHash;
setRequest.key = newEncKey[1].encryptedString;
async setupSubmitActions() {
this.kdf = KdfType.PBKDF2_SHA256;
const useLowerKdf = this.platformUtilsService.isEdge() || this.platformUtilsService.isIE();
this.kdfIterations = useLowerKdf ? 10000 : 100000;
return true;
}
async performSubmitActions(masterPasswordHash: string, key: SymmetricCryptoKey,
encKey: [SymmetricCryptoKey, CipherString]) {
const request = new SetPasswordRequest();
request.masterPasswordHash = masterPasswordHash;
request.key = encKey[1].encryptedString;
request.masterPasswordHint = this.hint;
request.kdf = this.kdf;
request.kdfIterations = this.kdfIterations;
const keys = await this.cryptoService.makeKeyPair(encKey[0]);
request.keys = new KeysRequest(keys[0], keys[1].encryptedString);
try {
this.formPromise = this.apiService.setPassword(setRequest);
this.formPromise = this.apiService.setPassword(request);
await this.formPromise;
await this.userService.setInformation(await this.userService.getUserId(), await this.userService.getEmail(),
this.kdf, this.kdfIterations);
await this.cryptoService.setKey(key);
await this.cryptoService.setKeyHash(masterPasswordHash);
await this.cryptoService.setEncKey(encKey[1].encryptedString);
await this.cryptoService.setEncPrivateKey(keys[1].encryptedString);
if (this.onSuccessfulChangePassword != null) {
this.onSuccessfulChangePassword();
} else {
@ -62,4 +88,10 @@ export class ChangePasswordComponent extends BaseChangePasswordComponent {
this.platformUtilsService.showToast('error', null, this.i18nService.t('errorOccurred'));
}
}
togglePassword(confirmField: boolean) {
this.platformUtilsService.eventTrack('Toggled Master Password on Set Password');
this.showPassword = !this.showPassword;
document.getElementById(confirmField ? 'masterPasswordRetype' : 'masterPassword').focus();
}
}

View File

@ -108,7 +108,6 @@ const routes: Routes = [
},
{
path: 'change-password', component: ChangePasswordComponent,
canActivate: [UnauthGuardService],
data: { titleId: 'setMasterPassword' },
},
{

View File

@ -28,18 +28,18 @@
<div class="row">
<div class="col-6">
<div class="form-group">
<label for="newMasterPassword">{{'newMasterPass' | i18n}}</label>
<input id="newMasterPassword" type="password" name="NewMasterPasswordHash" class="form-control mb-1"
[(ngModel)]="newMasterPassword" (input)="updatePasswordStrength()" required appInputVerbatim
<label for="masterPassword">{{'newMasterPass' | i18n}}</label>
<input id="masterPassword" type="password" name="NewMasterPasswordHash" class="form-control mb-1"
[(ngModel)]="masterPassword" (input)="updatePasswordStrength()" required appInputVerbatim
autocomplete="new-password">
<app-password-strength [score]="masterPasswordScore" [showText]="true"></app-password-strength>
</div>
</div>
<div class="col-6">
<div class="form-group">
<label for="confirmNewMasterPassword">{{'confirmNewMasterPass' | i18n}}</label>
<input id="confirmNewMasterPassword" type="password" name="ConfirmNewMasterPasswordHash"
class="form-control" [(ngModel)]="confirmNewMasterPassword" required appInputVerbatim
<label for="masterPasswordRetype">{{'confirmNewMasterPass' | i18n}}</label>
<input id="masterPasswordRetype" type="password" name="MasterPasswordRetype"
class="form-control" [(ngModel)]="masterPasswordRetype" required appInputVerbatim
autocomplete="new-password">
</div>
</div>

View File

@ -79,6 +79,16 @@ export class ChangePasswordComponent extends BaseChangePasswordComponent {
}
}
async submit() {
const hasEncKey = await this.cryptoService.hasEncKey();
if (!hasEncKey) {
this.platformUtilsService.showToast('error', null, this.i18nService.t('updateKey'));
return;
}
await super.submit();
}
async setupSubmitActions() {
if (this.currentMasterPassword == null || this.currentMasterPassword === '') {
this.platformUtilsService.showToast('error', this.i18nService.t('errorOccurred'),
@ -90,7 +100,7 @@ export class ChangePasswordComponent extends BaseChangePasswordComponent {
await this.syncService.fullSync(true);
}
super.setupSubmitActions();
return super.setupSubmitActions();
}
async performSubmitActions(newMasterPasswordHash: string, newKey: SymmetricCryptoKey,

View File

@ -3168,7 +3168,7 @@
"message": "Set Master Password"
},
"ssoCompleteRegistration": {
"message": "In order to complete logging in with SSO, please set a master password below. Make sure to choose a strong password/passphrase and comply with all applied organizational policies."
"message": "In order to complete logging in with SSO, please set a master password to access and protect your vault."
},
"identifier": {
"message": "Identifier"