mirror of
https://github.com/bitwarden/browser.git
synced 2024-11-22 11:45:59 +01:00
[PM-4260] [BEEEP] Mask TOTP seeds in cipher edit view - similar to how the password is hidden (#6649)
* PoC disallow changing masked values in edit mode and mask TOTP with password * toggle totp seed visibility independently from password visibility in edit mode * cleanup * add fallback value for when a cipher returns a null value for maskedPassword * toggle masks off for maskable login properties with no value on load * do not show mask toggle for password or totp if no value is present
This commit is contained in:
parent
c53db92f8a
commit
eae845d900
@ -70,15 +70,18 @@
|
|||||||
<div class="row-main">
|
<div class="row-main">
|
||||||
<label for="loginPassword">{{ "password" | i18n }}</label>
|
<label for="loginPassword">{{ "password" | i18n }}</label>
|
||||||
<input
|
<input
|
||||||
|
*ngIf="showPassword"
|
||||||
id="loginPassword"
|
id="loginPassword"
|
||||||
class="monospaced"
|
class="monospaced"
|
||||||
type="{{ showPassword ? 'text' : 'password' }}"
|
type="text"
|
||||||
name="Login.Password"
|
name="Login.Password"
|
||||||
[(ngModel)]="cipher.login.password"
|
[(ngModel)]="cipher.login.password"
|
||||||
appInputVerbatim
|
appInputVerbatim
|
||||||
[disabled]="!cipher.viewPassword"
|
|
||||||
[readonly]="!cipher.edit && editMode"
|
[readonly]="!cipher.edit && editMode"
|
||||||
/>
|
/>
|
||||||
|
<div *ngIf="!showPassword" class="monospaced">
|
||||||
|
{{ cipher.login.maskedPassword || "••••••••" }}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="action-buttons">
|
<div class="action-buttons">
|
||||||
<button
|
<button
|
||||||
@ -108,7 +111,7 @@
|
|||||||
appStopClick
|
appStopClick
|
||||||
appA11yTitle="{{ 'toggleVisibility' | i18n }}"
|
appA11yTitle="{{ 'toggleVisibility' | i18n }}"
|
||||||
(click)="togglePassword()"
|
(click)="togglePassword()"
|
||||||
*ngIf="cipher.viewPassword"
|
*ngIf="cipher.viewPassword && cipher.login.password"
|
||||||
[attr.aria-pressed]="showPassword"
|
[attr.aria-pressed]="showPassword"
|
||||||
>
|
>
|
||||||
<i
|
<i
|
||||||
@ -150,17 +153,35 @@
|
|||||||
<div class="row-main">
|
<div class="row-main">
|
||||||
<label for="loginTotp">{{ "authenticatorKeyTotp" | i18n }}</label>
|
<label for="loginTotp">{{ "authenticatorKeyTotp" | i18n }}</label>
|
||||||
<input
|
<input
|
||||||
|
*ngIf="showTotpSeed"
|
||||||
id="loginTotp"
|
id="loginTotp"
|
||||||
type="{{ cipher.viewPassword ? 'text' : 'password' }}"
|
type="text"
|
||||||
name="Login.Totp"
|
name="Login.Totp"
|
||||||
class="monospaced"
|
class="monospaced"
|
||||||
[(ngModel)]="cipher.login.totp"
|
[(ngModel)]="cipher.login.totp"
|
||||||
appInputVerbatim
|
appInputVerbatim
|
||||||
[disabled]="!cipher.viewPassword"
|
|
||||||
[readonly]="!cipher.edit && editMode"
|
[readonly]="!cipher.edit && editMode"
|
||||||
/>
|
/>
|
||||||
|
<div *ngIf="!showTotpSeed" class="monospaced">
|
||||||
|
{{ cipher.login.maskedPassword || "••••••••" }}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="action-buttons">
|
<div class="action-buttons">
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
class="row-btn"
|
||||||
|
appStopClick
|
||||||
|
appA11yTitle="{{ 'toggleVisibility' | i18n }}"
|
||||||
|
(click)="toggleTotpSeed()"
|
||||||
|
*ngIf="cipher.viewPassword && cipher.login.totp"
|
||||||
|
[attr.aria-pressed]="showTotpSeed"
|
||||||
|
>
|
||||||
|
<i
|
||||||
|
class="bwi bwi-lg"
|
||||||
|
aria-hidden="true"
|
||||||
|
[ngClass]="{ 'bwi-eye': !showTotpSeed, 'bwi-eye-slash': showTotpSeed }"
|
||||||
|
></i>
|
||||||
|
</button>
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
class="row-btn"
|
class="row-btn"
|
||||||
|
@ -64,6 +64,7 @@ export class AddEditComponent implements OnInit, OnDestroy {
|
|||||||
restorePromise: Promise<any>;
|
restorePromise: Promise<any>;
|
||||||
checkPasswordPromise: Promise<number>;
|
checkPasswordPromise: Promise<number>;
|
||||||
showPassword = false;
|
showPassword = false;
|
||||||
|
showTotpSeed = false;
|
||||||
showCardNumber = false;
|
showCardNumber = false;
|
||||||
showCardCode = false;
|
showCardCode = false;
|
||||||
cipherType = CipherType;
|
cipherType = CipherType;
|
||||||
@ -216,6 +217,8 @@ export class AddEditComponent implements OnInit, OnDestroy {
|
|||||||
if (!this.allowPersonal && this.organizationId == undefined) {
|
if (!this.allowPersonal && this.organizationId == undefined) {
|
||||||
this.organizationId = this.defaultOwnerId;
|
this.organizationId = this.defaultOwnerId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.resetMaskState();
|
||||||
}
|
}
|
||||||
|
|
||||||
async load() {
|
async load() {
|
||||||
@ -262,6 +265,8 @@ export class AddEditComponent implements OnInit, OnDestroy {
|
|||||||
this.cipher.secureNote.type = SecureNoteType.Generic;
|
this.cipher.secureNote.type = SecureNoteType.Generic;
|
||||||
this.cipher.reprompt = CipherRepromptType.None;
|
this.cipher.reprompt = CipherRepromptType.None;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.resetMaskState();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.cipher != null && (!this.editMode || loadedAddEditCipherInfo || this.cloneMode)) {
|
if (this.cipher != null && (!this.editMode || loadedAddEditCipherInfo || this.cloneMode)) {
|
||||||
@ -501,10 +506,18 @@ export class AddEditComponent implements OnInit, OnDestroy {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
resetMaskState() {
|
||||||
|
// toggle masks off for maskable login properties with no value on init/load
|
||||||
|
this.showTotpSeed = !this.cipher.login?.totp;
|
||||||
|
this.showPassword = !this.cipher.login?.password;
|
||||||
|
}
|
||||||
|
|
||||||
togglePassword() {
|
togglePassword() {
|
||||||
this.showPassword = !this.showPassword;
|
this.showPassword = !this.showPassword;
|
||||||
document.getElementById("loginPassword").focus();
|
|
||||||
if (this.editMode && this.showPassword) {
|
if (this.editMode && this.showPassword) {
|
||||||
|
document.getElementById("loginPassword")?.focus();
|
||||||
|
|
||||||
this.eventCollectionService.collect(
|
this.eventCollectionService.collect(
|
||||||
EventType.Cipher_ClientToggledPasswordVisible,
|
EventType.Cipher_ClientToggledPasswordVisible,
|
||||||
this.cipherId,
|
this.cipherId,
|
||||||
@ -512,6 +525,19 @@ export class AddEditComponent implements OnInit, OnDestroy {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
toggleTotpSeed() {
|
||||||
|
this.showTotpSeed = !this.showTotpSeed;
|
||||||
|
|
||||||
|
if (this.editMode && this.showTotpSeed) {
|
||||||
|
document.getElementById("loginTotp")?.focus();
|
||||||
|
|
||||||
|
this.eventCollectionService.collect(
|
||||||
|
EventType.Cipher_ClientToggledTOTPSeedVisible,
|
||||||
|
this.cipherId,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
async toggleCardNumber() {
|
async toggleCardNumber() {
|
||||||
this.showCardNumber = !this.showCardNumber;
|
this.showCardNumber = !this.showCardNumber;
|
||||||
if (this.showCardNumber) {
|
if (this.showCardNumber) {
|
||||||
|
@ -30,6 +30,7 @@ export enum EventType {
|
|||||||
Cipher_SoftDeleted = 1115,
|
Cipher_SoftDeleted = 1115,
|
||||||
Cipher_Restored = 1116,
|
Cipher_Restored = 1116,
|
||||||
Cipher_ClientToggledCardNumberVisible = 1117,
|
Cipher_ClientToggledCardNumberVisible = 1117,
|
||||||
|
Cipher_ClientToggledTOTPSeedVisible = 1118,
|
||||||
|
|
||||||
Collection_Created = 1300,
|
Collection_Created = 1300,
|
||||||
Collection_Updated = 1301,
|
Collection_Updated = 1301,
|
||||||
|
Loading…
Reference in New Issue
Block a user