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:
@@ -268,6 +268,9 @@
|
||||
"length": {
|
||||
"message": "Length"
|
||||
},
|
||||
"passwordMinLength": {
|
||||
"message": "Minimum password length"
|
||||
},
|
||||
"uppercase": {
|
||||
"message": "Uppercase (A-Z)"
|
||||
},
|
||||
|
||||
@@ -341,7 +341,8 @@
|
||||
}
|
||||
}
|
||||
|
||||
.img-right {
|
||||
.img-right,
|
||||
.txt-right {
|
||||
float: right;
|
||||
margin-left: 10px;
|
||||
}
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -403,6 +403,9 @@
|
||||
"length": {
|
||||
"message": "Length"
|
||||
},
|
||||
"passwordMinLength": {
|
||||
"message": "Minimum password length"
|
||||
},
|
||||
"uppercase": {
|
||||
"message": "Uppercase (A-Z)"
|
||||
},
|
||||
|
||||
@@ -217,7 +217,8 @@
|
||||
}
|
||||
}
|
||||
|
||||
.img-right {
|
||||
.img-right,
|
||||
.txt-right {
|
||||
float: right;
|
||||
margin-left: 10px;
|
||||
}
|
||||
|
||||
@@ -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 }}"
|
||||
/>
|
||||
|
||||
@@ -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."
|
||||
|
||||
Reference in New Issue
Block a user