password strength checks during registration

This commit is contained in:
Kyle Spearrin 2018-11-12 22:54:40 -05:00
parent 2664059812
commit 85c0ddba10
9 changed files with 86 additions and 6 deletions

2
jslib

@ -1 +1 @@
Subproject commit 786fa02b90d64044aee23011a18f6e202856a362 Subproject commit aa16fb2a9e4b6fb33ed80dea2a4c7bfa2234d45c

5
package-lock.json generated
View File

@ -12003,6 +12003,11 @@
"version": "0.8.26", "version": "0.8.26",
"resolved": "https://registry.npmjs.org/zone.js/-/zone.js-0.8.26.tgz", "resolved": "https://registry.npmjs.org/zone.js/-/zone.js-0.8.26.tgz",
"integrity": "sha512-W9Nj+UmBJG251wkCacIkETgra4QgBo/vgoEkb4a2uoLzpQG7qF9nzwoLXWU5xj3Fg2mxGvEDh47mg24vXccYjA==" "integrity": "sha512-W9Nj+UmBJG251wkCacIkETgra4QgBo/vgoEkb4a2uoLzpQG7qF9nzwoLXWU5xj3Fg2mxGvEDh47mg24vXccYjA=="
},
"zxcvbn": {
"version": "4.4.2",
"resolved": "https://registry.npmjs.org/zxcvbn/-/zxcvbn-4.4.2.tgz",
"integrity": "sha1-KOwXzwl0PtyrBW3dixsGJizHPDA="
} }
} }
} }

View File

@ -88,6 +88,7 @@
"web-animations-js": "2.3.1", "web-animations-js": "2.3.1",
"webcrypto-shim": "0.1.4", "webcrypto-shim": "0.1.4",
"whatwg-fetch": "3.0.0", "whatwg-fetch": "3.0.0",
"zone.js": "0.8.26" "zone.js": "0.8.26",
"zxcvbn": "4.4.2"
} }
} }

View File

@ -21,8 +21,11 @@
<div class="form-group"> <div class="form-group">
<label for="masterPassword">{{'masterPass' | i18n}}</label> <label for="masterPassword">{{'masterPass' | i18n}}</label>
<div class="d-flex"> <div class="d-flex">
<input id="masterPassword" type="{{showPassword ? 'text' : 'password'}}" name="MasterPassword" class="text-monospace form-control" <div class="w-100">
[(ngModel)]="masterPassword" required appInputVerbatim> <input id="masterPassword" type="{{showPassword ? 'text' : 'password'}}" name="MasterPassword" class="text-monospace form-control mb-1"
[(ngModel)]="masterPassword" (input)="updatePasswordStrength()" required appInputVerbatim>
<app-password-strength [score]="masterPasswordScore" [showText]="true"></app-password-strength>
</div>
<button type="button" class="ml-1 btn btn-link" title="{{'toggleVisibility' | i18n}}" (click)="togglePassword(false)"> <button type="button" class="ml-1 btn btn-link" title="{{'toggleVisibility' | i18n}}" (click)="togglePassword(false)">
<i class="fa fa-lg" [ngClass]="{'fa-eye': !showPassword, 'fa-eye-slash': showPassword}"></i> <i class="fa fa-lg" [ngClass]="{'fa-eye': !showPassword, 'fa-eye-slash': showPassword}"></i>
</button> </button>

View File

@ -8,6 +8,7 @@ import { ApiService } from 'jslib/abstractions/api.service';
import { AuthService } from 'jslib/abstractions/auth.service'; import { AuthService } from 'jslib/abstractions/auth.service';
import { CryptoService } from 'jslib/abstractions/crypto.service'; import { CryptoService } from 'jslib/abstractions/crypto.service';
import { I18nService } from 'jslib/abstractions/i18n.service'; import { I18nService } from 'jslib/abstractions/i18n.service';
import { PasswordGenerationService } from 'jslib/abstractions/passwordGeneration.service';
import { PlatformUtilsService } from 'jslib/abstractions/platformUtils.service'; import { PlatformUtilsService } from 'jslib/abstractions/platformUtils.service';
import { StateService } from 'jslib/abstractions/state.service'; import { StateService } from 'jslib/abstractions/state.service';
@ -24,8 +25,10 @@ export class RegisterComponent extends BaseRegisterComponent {
constructor(authService: AuthService, router: Router, constructor(authService: AuthService, router: Router,
i18nService: I18nService, cryptoService: CryptoService, i18nService: I18nService, cryptoService: CryptoService,
apiService: ApiService, private route: ActivatedRoute, apiService: ApiService, private route: ActivatedRoute,
stateService: StateService, platformUtilsService: PlatformUtilsService) { stateService: StateService, platformUtilsService: PlatformUtilsService,
super(authService, router, i18nService, cryptoService, apiService, stateService, platformUtilsService); passwordGenerationService: PasswordGenerationService) {
super(authService, router, i18nService, cryptoService, apiService, stateService, platformUtilsService,
passwordGenerationService);
this.showTerms = !platformUtilsService.isSelfHost(); this.showTerms = !platformUtilsService.isSelfHost();
} }

View File

@ -18,6 +18,7 @@ import { ModalComponent } from './modal.component';
import { AvatarComponent } from './components/avatar.component'; import { AvatarComponent } from './components/avatar.component';
import { CalloutComponent } from './components/callout.component'; import { CalloutComponent } from './components/callout.component';
import { PasswordStrengthComponent } from './components/password-strength.component';
import { FooterComponent } from './layouts/footer.component'; import { FooterComponent } from './layouts/footer.component';
import { FrontendLayoutComponent } from './layouts/frontend-layout.component'; import { FrontendLayoutComponent } from './layouts/frontend-layout.component';
@ -291,6 +292,7 @@ registerLocaleData(localeZhCn, 'zh-CN');
VerifyEmailComponent, VerifyEmailComponent,
VerifyEmailTokenComponent, VerifyEmailTokenComponent,
VerifyRecoverDeleteComponent, VerifyRecoverDeleteComponent,
PasswordStrengthComponent,
], ],
entryComponents: [ entryComponents: [
AddEditComponent, AddEditComponent,

View File

@ -0,0 +1,8 @@
<div class="progress">
<div class="progress-bar {{color}}" role="progressbar" [ngStyle]="{width: (scoreWidth + '%')}" aria-valuenow="scoreWidth"
aria-valuemin="0" aria-valuemax="100">
<ng-container *ngIf="showText && text">
{{text}}
</ng-container>
</div>
</div>

View File

@ -0,0 +1,44 @@
import {
Component,
Input,
OnChanges,
} from '@angular/core';
import { I18nService } from 'jslib/abstractions/i18n.service';
@Component({
selector: 'app-password-strength',
templateUrl: 'password-strength.component.html',
})
export class PasswordStrengthComponent implements OnChanges {
@Input() score?: number;
@Input() showText = false;
scoreWidth = 0;
color = 'bg-danger';
text: string;
constructor(private i18nService: I18nService) { }
ngOnChanges(): void {
this.scoreWidth = this.score == null ? 0 : (this.score + 1) * 20;
switch (this.score) {
case 4:
this.color = 'bg-success';
this.text = this.i18nService.t('strong');
break;
case 3:
this.color = 'bg-warning';
this.text = this.i18nService.t('ok');
break;
case 2:
this.color = 'bg-warning';
this.text = this.i18nService.t('weak');
break;
default:
this.color = 'bg-danger';
this.text = this.score != null ? this.i18nService.t('weak') : null;
break;
}
}
}

View File

@ -2512,5 +2512,19 @@
}, },
"whoOwnsThisItem": { "whoOwnsThisItem": {
"message": "Who owns this item?" "message": "Who owns this item?"
},
"strong": {
"message": "Strong",
"description": "ex. Strong password"
},
"weak": {
"message": "Weak",
"description": "ex. Weak password"
},
"weakMasterPassword": {
"message": "Weak Master Password"
},
"weakMasterPasswordDesc": {
"message": "The master password you have chosen is weak. You should use a strong master password to properly protect your Bitwarden account. Are you sure you want to use this master password?"
} }
} }