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

[PM-252] fix inconsistent generator configuration behavior (#6755)

* decompose password generator policy enforcement
* integrate new logic with UI
* improve UX of minimum password length
* improve password generator policy options documentation
* initialize min length to default minimum length boundary
* reset form value on input to prevent UI desync from model

---------

Co-authored-by: Thomas Rittson <31796059+eliykat@users.noreply.github.com>
This commit is contained in:
✨ Audrey ✨
2023-12-12 19:17:20 -05:00
committed by GitHub
parent bfa76885ac
commit df406a9862
16 changed files with 1532 additions and 201 deletions

View File

@@ -268,6 +268,9 @@
"length": {
"message": "Length"
},
"passwordMinLength": {
"message": "Minimum password length"
},
"uppercase": {
"message": "Uppercase (A-Z)"
},

View File

@@ -341,7 +341,8 @@
}
}
.img-right {
.img-right,
.txt-right {
float: right;
margin-left: 10px;
}

View File

@@ -176,7 +176,7 @@
<input
id="length"
type="number"
min="5"
[min]="passwordOptions.minLength"
max="128"
[(ngModel)]="passwordOptions.length"
(change)="savePasswordOptions()"
@@ -184,7 +184,7 @@
<input
id="lengthRange"
type="range"
min="5"
[min]="passwordOptions.minLength"
max="128"
step="1"
[(ngModel)]="passwordOptions.length"
@@ -194,6 +194,18 @@
tabindex="-1"
/>
</div>
<div class="box-content-row" appBoxRow>
<span>{{ "passwordMinLength" | i18n }}</span>
<span
class="sr-only"
attr.aria-label="{{ 'passwordMinLength' | i18n }}"
role="status"
aria-live="polite"
>
{{ passwordOptionsMinLengthForReader$ | async }}
</span>
<span class="txt-right">{{ passwordOptions.minLength }}</span>
</div>
<div class="box-content-row box-content-row-checkbox" appBoxRow>
<label for="uppercase">A-Z</label>
<input
@@ -221,10 +233,10 @@
<input
id="numbers"
type="checkbox"
(change)="savePasswordOptions()"
attr.aria-label="{{ 'numbers' | i18n }}"
[disabled]="enforcedPasswordPolicyOptions.useNumbers"
[(ngModel)]="passwordOptions.number"
[ngModel]="passwordOptions.number"
(ngModelChange)="setPasswordOptionsNumber($event)"
/>
</div>
<div class="box-content-row box-content-row-checkbox" appBoxRow>
@@ -232,10 +244,10 @@
<input
id="special"
type="checkbox"
(change)="savePasswordOptions()"
attr.aria-label="{{ 'specialCharacters' | i18n }}"
[disabled]="enforcedPasswordPolicyOptions.useSpecial"
[(ngModel)]="passwordOptions.special"
[ngModel]="passwordOptions.special"
(ngModelChange)="setPasswordOptionsSpecial($event)"
/>
</div>
</div>
@@ -249,8 +261,8 @@
type="number"
min="0"
max="9"
(change)="savePasswordOptions()"
[(ngModel)]="passwordOptions.minNumber"
(input)="onPasswordOptionsMinNumberInput($event)"
/>
</div>
<div class="box-content-row box-content-row-input" appBoxRow>
@@ -260,8 +272,8 @@
type="number"
min="0"
max="9"
(change)="savePasswordOptions()"
[(ngModel)]="passwordOptions.minSpecial"
(input)="onPasswordOptionsMinSpecialInput($event)"
/>
</div>
<div class="box-content-row box-content-row-checkbox" appBoxRow>

View File

@@ -200,7 +200,7 @@
<input
id="length"
type="number"
min="5"
[min]="passwordOptions.minLength"
max="128"
[(ngModel)]="passwordOptions.length"
(blur)="savePasswordOptions()"
@@ -208,7 +208,7 @@
<input
id="lengthRange"
type="range"
min="5"
[min]="passwordOptions.minLength"
max="128"
step="1"
[(ngModel)]="passwordOptions.length"
@@ -218,6 +218,18 @@
tabindex="-1"
/>
</div>
<div class="box-content-row" appBoxRow>
<span>{{ "passwordMinLength" | i18n }}</span>
<span class="txt-right">{{ passwordOptions.minLength }}</span>
<span
class="sr-only"
attr.aria-label="{{ 'passwordMinLength' | i18n }}"
role="status"
aria-live="polite"
>
{{ passwordOptionsMinLengthForReader$ | async }}
</span>
</div>
<div class="box-content-row box-content-row-checkbox" appBoxRow>
<label for="uppercase">A-Z</label>
<input
@@ -247,7 +259,8 @@
type="checkbox"
(change)="savePasswordOptions()"
[disabled]="enforcedPasswordPolicyOptions?.useNumbers"
[(ngModel)]="passwordOptions.number"
[ngModel]="passwordOptions.number"
(ngModelChange)="setPasswordOptionsNumber($event)"
attr.aria-label="{{ 'numbers' | i18n }}"
/>
</div>
@@ -258,7 +271,8 @@
type="checkbox"
(change)="savePasswordOptions()"
[disabled]="enforcedPasswordPolicyOptions?.useSpecial"
[(ngModel)]="passwordOptions.special"
[ngModel]="passwordOptions.special"
(ngModelChange)="setPasswordOptionsSpecial($event)"
attr.aria-label="{{ 'specialCharacters' | i18n }}"
/>
</div>
@@ -275,6 +289,7 @@
max="9"
(change)="savePasswordOptions()"
[(ngModel)]="passwordOptions.minNumber"
(input)="onPasswordOptionsMinNumberInput($event)"
/>
</div>
<div class="box-content-row box-content-row-input" appBoxRow>
@@ -286,6 +301,7 @@
max="9"
(change)="savePasswordOptions()"
[(ngModel)]="passwordOptions.minSpecial"
(input)="onPasswordOptionsMinSpecialInput($event)"
/>
</div>
<div class="box-content-row box-content-row-checkbox" appBoxRow>

View File

@@ -403,6 +403,9 @@
"length": {
"message": "Length"
},
"passwordMinLength": {
"message": "Minimum password length"
},
"uppercase": {
"message": "Uppercase (A-Z)"
},

View File

@@ -217,7 +217,8 @@
}
}
.img-right {
.img-right,
.txt-right {
float: right;
margin-left: 10px;
}

View File

@@ -109,13 +109,31 @@
id="length"
class="form-control"
type="number"
min="5"
[min]="passwordOptions.minLength"
max="128"
[(ngModel)]="passwordOptions.length"
(blur)="savePasswordOptions()"
(change)="lengthChanged()"
/>
</div>
<div class="form-group col-4">
<label for="min-length">{{ "passwordMinLength" | i18n }}</label>
<input
id="min-length"
class="form-control"
type="text"
readonly="true"
[value]="passwordOptions.length"
/>
<span
class="sr-only"
attr.aria-label="{{ 'passwordMinLength' | i18n }}"
role="status"
aria-live="polite"
>
{{ passwordOptionsMinLengthForReader$ | async }}
</span>
</div>
<div class="form-group col-4">
<label for="min-number">{{ "minNumbers" | i18n }}</label>
<input
@@ -124,8 +142,8 @@
type="number"
min="0"
max="9"
(blur)="savePasswordOptions()"
[(ngModel)]="passwordOptions.minNumber"
(input)="onPasswordOptionsMinNumberInput($event)"
(change)="minNumberChanged()"
/>
</div>
@@ -137,8 +155,8 @@
type="number"
min="0"
max="9"
(blur)="savePasswordOptions()"
[(ngModel)]="passwordOptions.minSpecial"
(input)="onPasswordOptionsMinSpecialInput($event)"
(change)="minSpecialChanged()"
/>
</div>
@@ -175,7 +193,8 @@
class="form-check-input"
type="checkbox"
(change)="savePasswordOptions()"
[(ngModel)]="passwordOptions.number"
[ngModel]="passwordOptions.number"
(ngModelChange)="setPasswordOptionsNumber($event)"
[disabled]="enforcedPasswordPolicyOptions?.useNumbers"
attr.aria-label="{{ 'numbers' | i18n }}"
/>
@@ -186,8 +205,8 @@
id="special"
class="form-check-input"
type="checkbox"
(change)="savePasswordOptions()"
[(ngModel)]="passwordOptions.special"
[ngModel]="passwordOptions.special"
(ngModelChange)="setPasswordOptionsSpecial($event)"
[disabled]="enforcedPasswordPolicyOptions?.useSpecial"
attr.aria-label="{{ 'specialCharacters' | i18n }}"
/>

View File

@@ -1150,6 +1150,9 @@
"length": {
"message": "Length"
},
"passwordMinLength": {
"message": "Minimum password length"
},
"uppercase": {
"message": "Uppercase (A-Z)",
"description": "Include uppercase letters in the password generator."