mirror of
https://github.com/bitwarden/desktop.git
synced 2024-11-28 12:35:40 +01:00
password breach check moved to view page
This commit is contained in:
parent
df9d79ab7d
commit
093071c8f3
2
jslib
2
jslib
@ -1 +1 @@
|
|||||||
Subproject commit ab00dfd3991c258065d452dfb14b11e90898143e
|
Subproject commit e3b3e444dbff7e4541fa5367ee26bc7ed4d73b26
|
@ -35,10 +35,6 @@
|
|||||||
[(ngModel)]="cipher.login.password">
|
[(ngModel)]="cipher.login.password">
|
||||||
</div>
|
</div>
|
||||||
<div class="action-buttons">
|
<div class="action-buttons">
|
||||||
<a class="row-btn" href="#" appStopClick appBlurClick
|
|
||||||
title="{{'checkPassword' | i18n}}" (click)="checkPassword()">
|
|
||||||
<i class="fa fa-lg fa-check-circle"></i>
|
|
||||||
</a>
|
|
||||||
<a class="row-btn" href="#" appStopClick appBlurClick
|
<a class="row-btn" href="#" appStopClick appBlurClick
|
||||||
title="{{'toggleVisibility' | i18n}}" (click)="togglePassword()">
|
title="{{'toggleVisibility' | i18n}}" (click)="togglePassword()">
|
||||||
<i class="fa fa-lg"
|
<i class="fa fa-lg"
|
||||||
|
@ -15,7 +15,6 @@ import { CipherType } from 'jslib/enums/cipherType';
|
|||||||
import { FieldType } from 'jslib/enums/fieldType';
|
import { FieldType } from 'jslib/enums/fieldType';
|
||||||
import { SecureNoteType } from 'jslib/enums/secureNoteType';
|
import { SecureNoteType } from 'jslib/enums/secureNoteType';
|
||||||
|
|
||||||
import { AuditService } from 'jslib/abstractions/audit.service';
|
|
||||||
import { CipherService } from 'jslib/abstractions/cipher.service';
|
import { CipherService } from 'jslib/abstractions/cipher.service';
|
||||||
import { FolderService } from 'jslib/abstractions/folder.service';
|
import { FolderService } from 'jslib/abstractions/folder.service';
|
||||||
import { I18nService } from 'jslib/abstractions/i18n.service';
|
import { I18nService } from 'jslib/abstractions/i18n.service';
|
||||||
@ -61,8 +60,7 @@ export class AddEditComponent implements OnChanges {
|
|||||||
|
|
||||||
constructor(private cipherService: CipherService, private folderService: FolderService,
|
constructor(private cipherService: CipherService, private folderService: FolderService,
|
||||||
private i18nService: I18nService, private platformUtilsService: PlatformUtilsService,
|
private i18nService: I18nService, private platformUtilsService: PlatformUtilsService,
|
||||||
private analytics: Angulartics2, private toasterService: ToasterService,
|
private analytics: Angulartics2, private toasterService: ToasterService) {
|
||||||
private auditService: AuditService) {
|
|
||||||
this.typeOptions = [
|
this.typeOptions = [
|
||||||
{ name: i18nService.t('typeLogin'), value: CipherType.Login },
|
{ name: i18nService.t('typeLogin'), value: CipherType.Login },
|
||||||
{ name: i18nService.t('typeCard'), value: CipherType.Card },
|
{ name: i18nService.t('typeCard'), value: CipherType.Card },
|
||||||
@ -214,19 +212,6 @@ export class AddEditComponent implements OnChanges {
|
|||||||
document.getElementById('loginPassword').focus();
|
document.getElementById('loginPassword').focus();
|
||||||
}
|
}
|
||||||
|
|
||||||
async checkPassword() {
|
|
||||||
this.analytics.eventTrack.next({ action: 'Check Password' });
|
|
||||||
|
|
||||||
const match = await this.auditService.passwordLeaked(this.cipher.login.password);
|
|
||||||
|
|
||||||
if (match > 0) {
|
|
||||||
this.toasterService.popAsync('error', this.i18nService.t('errorOccurred'),
|
|
||||||
this.i18nService.t('passwordExposed', match.toString()));
|
|
||||||
} else {
|
|
||||||
this.toasterService.popAsync('success', null, this.i18nService.t('passwordSafe'));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
toggleFieldValue(field: FieldView) {
|
toggleFieldValue(field: FieldView) {
|
||||||
const f = (field as any);
|
const f = (field as any);
|
||||||
f.showValue = !f.showValue;
|
f.showValue = !f.showValue;
|
||||||
|
@ -47,6 +47,12 @@
|
|||||||
<span [hidden]="!showPassword" class="monospaced">{{cipher.login.password}}</span>
|
<span [hidden]="!showPassword" class="monospaced">{{cipher.login.password}}</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="action-buttons">
|
<div class="action-buttons">
|
||||||
|
<button type="button" #checkPasswordBtn class="row-btn btn" appBlurClick
|
||||||
|
title="{{'checkPassword' | i18n}}" (click)="checkPassword()"
|
||||||
|
[appApiAction]="checkPasswordPromise" [disabled]="checkPasswordBtn.loading">
|
||||||
|
<i class="fa fa-lg fa-check-circle" [hidden]="checkPasswordBtn.loading"></i>
|
||||||
|
<i class="fa fa-lg fa-spinner fa-spin" [hidden]="!checkPasswordBtn.loading"></i>
|
||||||
|
</button>
|
||||||
<a class="row-btn" href="#" appStopClick title="{{'toggleVisibility' | i18n}}"
|
<a class="row-btn" href="#" appStopClick title="{{'toggleVisibility' | i18n}}"
|
||||||
(click)="togglePassword()">
|
(click)="togglePassword()">
|
||||||
<i class="fa fa-lg"
|
<i class="fa fa-lg"
|
||||||
|
@ -15,6 +15,7 @@ import { Angulartics2 } from 'angulartics2';
|
|||||||
import { CipherType } from 'jslib/enums/cipherType';
|
import { CipherType } from 'jslib/enums/cipherType';
|
||||||
import { FieldType } from 'jslib/enums/fieldType';
|
import { FieldType } from 'jslib/enums/fieldType';
|
||||||
|
|
||||||
|
import { AuditService } from 'jslib/abstractions/audit.service';
|
||||||
import { CipherService } from 'jslib/abstractions/cipher.service';
|
import { CipherService } from 'jslib/abstractions/cipher.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';
|
||||||
@ -42,13 +43,15 @@ export class ViewComponent implements OnChanges, OnDestroy {
|
|||||||
totpSec: number;
|
totpSec: number;
|
||||||
totpLow: boolean;
|
totpLow: boolean;
|
||||||
fieldType = FieldType;
|
fieldType = FieldType;
|
||||||
|
checkPasswordPromise: Promise<number>;
|
||||||
|
|
||||||
private totpInterval: any;
|
private totpInterval: any;
|
||||||
|
|
||||||
constructor(private cipherService: CipherService, private totpService: TotpService,
|
constructor(private cipherService: CipherService, private totpService: TotpService,
|
||||||
private tokenService: TokenService, private toasterService: ToasterService,
|
private tokenService: TokenService, private toasterService: ToasterService,
|
||||||
private cryptoService: CryptoService, private platformUtilsService: PlatformUtilsService,
|
private cryptoService: CryptoService, private platformUtilsService: PlatformUtilsService,
|
||||||
private i18nService: I18nService, private analytics: Angulartics2) { }
|
private i18nService: I18nService, private analytics: Angulartics2,
|
||||||
|
private auditService: AuditService) { }
|
||||||
|
|
||||||
async ngOnChanges() {
|
async ngOnChanges() {
|
||||||
this.cleanUp();
|
this.cleanUp();
|
||||||
@ -82,6 +85,22 @@ export class ViewComponent implements OnChanges, OnDestroy {
|
|||||||
this.showPassword = !this.showPassword;
|
this.showPassword = !this.showPassword;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async checkPassword() {
|
||||||
|
if (this.cipher.login == null || this.cipher.login.password == null || this.cipher.login.password === '') {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.analytics.eventTrack.next({ action: 'Check Password' });
|
||||||
|
this.checkPasswordPromise = this.auditService.passwordLeaked(this.cipher.login.password);
|
||||||
|
const matches = await this.checkPasswordPromise;
|
||||||
|
|
||||||
|
if (matches > 0) {
|
||||||
|
this.toasterService.popAsync('warning', null, this.i18nService.t('passwordExposed', matches.toString()));
|
||||||
|
} else {
|
||||||
|
this.toasterService.popAsync('success', null, this.i18nService.t('passwordSafe'));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
toggleFieldValue(field: FieldView) {
|
toggleFieldValue(field: FieldView) {
|
||||||
const f = (field as any);
|
const f = (field as any);
|
||||||
f.showValue = !f.showValue;
|
f.showValue = !f.showValue;
|
||||||
|
@ -959,14 +959,14 @@
|
|||||||
"message": "Window"
|
"message": "Window"
|
||||||
},
|
},
|
||||||
"checkPassword": {
|
"checkPassword": {
|
||||||
"message": "Check if this password has been previously exposed."
|
"message": "Check if this password has been exposed."
|
||||||
},
|
},
|
||||||
"passwordExposed": {
|
"passwordExposed": {
|
||||||
"message": "This password has been exposed in $VALUE$ data breach(es)! You should change it.",
|
"message": "This password has been exposed $VALUE$ time(s) in data breaches. You should change it.",
|
||||||
"placeholders": {
|
"placeholders": {
|
||||||
"value": {
|
"value": {
|
||||||
"content": "$1",
|
"content": "$1",
|
||||||
"example": "1"
|
"example": "2"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -20,7 +20,7 @@ $brand-primary: #3c8dbc;
|
|||||||
$brand-danger: #dd4b39;
|
$brand-danger: #dd4b39;
|
||||||
$brand-success: #00a65a;
|
$brand-success: #00a65a;
|
||||||
$brand-info: #555555;
|
$brand-info: #555555;
|
||||||
$brand-warning: #f39c12;
|
$brand-warning: #bf7e16;
|
||||||
$brand-primary-accent: #286090;
|
$brand-primary-accent: #286090;
|
||||||
|
|
||||||
$background-color: white;
|
$background-color: white;
|
||||||
|
Loading…
Reference in New Issue
Block a user