445 lines
16 KiB
HTML
445 lines
16 KiB
HTML
<header>
|
|
<div class="left">
|
|
<app-pop-out [show]="!comingFromAddEdit"></app-pop-out>
|
|
<button type="button" appBlurClick (click)="close()" *ngIf="comingFromAddEdit">
|
|
{{ "cancel" | i18n }}
|
|
</button>
|
|
</div>
|
|
<h1 class="center">
|
|
<span class="title">{{ "generator" | i18n }}</span>
|
|
</h1>
|
|
<div class="right">
|
|
<button type="button" appBlurClick (click)="select()" *ngIf="comingFromAddEdit">
|
|
{{ "select" | i18n }}
|
|
</button>
|
|
</div>
|
|
</header>
|
|
<content>
|
|
<app-callout type="info" *ngIf="enforcedPasswordPolicyOptions?.inEffect() && type === 'password'">
|
|
{{ "passwordGeneratorPolicyInEffect" | i18n }}
|
|
</app-callout>
|
|
<div class="generated-block" *ngIf="type === 'password'">
|
|
<div class="generated-wrapper" [innerHTML]="password | colorPassword" appSelectCopy></div>
|
|
<div class="action-buttons">
|
|
<button
|
|
type="button"
|
|
class="row-btn"
|
|
appStopClick
|
|
appA11yTitle="{{ 'copyPassword' | i18n }}"
|
|
(click)="copy()"
|
|
>
|
|
<i class="bwi bwi-lg bwi-clone" aria-hidden="true"></i>
|
|
</button>
|
|
<button
|
|
type="button"
|
|
appStopClick
|
|
appBlurClick
|
|
appA11yTitle="{{ 'regeneratePassword' | i18n }}"
|
|
(click)="regenerate()"
|
|
>
|
|
<i class="bwi bwi-lg bwi-generate" aria-hidden="true"></i>
|
|
</button>
|
|
</div>
|
|
</div>
|
|
<div class="generated-block" *ngIf="type === 'username'">
|
|
<div class="generated-wrapper" [innerHTML]="username | colorPassword" appSelectCopy></div>
|
|
<div class="action-buttons">
|
|
<button
|
|
type="button"
|
|
class="row-btn"
|
|
appStopClick
|
|
appA11yTitle="{{ 'copyUsername' | i18n }}"
|
|
(click)="copy()"
|
|
>
|
|
<i class="bwi bwi-lg bwi-clone" aria-hidden="true"></i>
|
|
</button>
|
|
<button
|
|
type="button"
|
|
appStopClick
|
|
appBlurClick
|
|
appA11yTitle="{{ 'regenerateUsername' | i18n }}"
|
|
(click)="regenerate()"
|
|
>
|
|
<i class="bwi bwi-lg bwi-generate" aria-hidden="true"></i>
|
|
</button>
|
|
</div>
|
|
</div>
|
|
<div class="box">
|
|
<div class="box-content">
|
|
<div class="box-content-row">
|
|
<label class="radio-header">{{ "whatWouldYouLikeToGenerate" | i18n }}</label>
|
|
<div class="radio-group text-default" appBoxRow *ngFor="let o of typeOptions">
|
|
<input
|
|
type="radio"
|
|
[(ngModel)]="type"
|
|
name="Type_{{ o.value }}"
|
|
id="type_{{ o.value }}"
|
|
[value]="o.value"
|
|
(change)="typeChanged()"
|
|
[checked]="type === o.value"
|
|
[disabled]="comingFromAddEdit"
|
|
/>
|
|
<label for="type_{{ o.value }}">
|
|
{{ o.name }}
|
|
</label>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<ng-container *ngIf="type === 'password'">
|
|
<div class="box">
|
|
<h2 class="box-header">
|
|
{{ "options" | i18n }}
|
|
</h2>
|
|
<div class="box-content">
|
|
<div class="box-content-row">
|
|
<label class="radio-header">{{ "passwordType" | i18n }}</label>
|
|
<div class="radio-group text-default" appBoxRow *ngFor="let o of passTypeOptions">
|
|
<input
|
|
type="radio"
|
|
[(ngModel)]="passwordOptions.type"
|
|
name="PasswordType_{{ o.value }}"
|
|
id="passwordtype_{{ o.value }}"
|
|
[value]="o.value"
|
|
(change)="savePasswordOptions()"
|
|
[checked]="passwordOptions.type === o.value"
|
|
/>
|
|
<label for="passwordtype_{{ o.value }}">
|
|
{{ o.name }}
|
|
</label>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="box" *ngIf="passwordOptions.type === 'passphrase'">
|
|
<div class="box-content">
|
|
<div class="box-content-row box-content-row-input" appBoxRow>
|
|
<label for="num-words">{{ "numWords" | i18n }}</label>
|
|
<input
|
|
id="num-words"
|
|
type="number"
|
|
min="3"
|
|
max="20"
|
|
(change)="savePasswordOptions()"
|
|
[(ngModel)]="passwordOptions.numWords"
|
|
/>
|
|
</div>
|
|
<div class="box-content-row box-content-row-input" appBoxRow>
|
|
<label for="word-separator">{{ "wordSeparator" | i18n }}</label>
|
|
<input
|
|
id="word-separator"
|
|
type="text"
|
|
maxlength="1"
|
|
(input)="savePasswordOptions()"
|
|
[(ngModel)]="passwordOptions.wordSeparator"
|
|
/>
|
|
</div>
|
|
<div class="box-content-row box-content-row-checkbox" appBoxRow>
|
|
<label for="capitalize">{{ "capitalize" | i18n }}</label>
|
|
<input
|
|
id="capitalize"
|
|
type="checkbox"
|
|
(change)="savePasswordOptions()"
|
|
[(ngModel)]="passwordOptions.capitalize"
|
|
[disabled]="enforcedPasswordPolicyOptions?.capitalize"
|
|
/>
|
|
</div>
|
|
<div class="box-content-row box-content-row-checkbox" appBoxRow>
|
|
<label for="include-number">{{ "includeNumber" | i18n }}</label>
|
|
<input
|
|
id="include-number"
|
|
type="checkbox"
|
|
(change)="savePasswordOptions()"
|
|
[(ngModel)]="passwordOptions.includeNumber"
|
|
[disabled]="enforcedPasswordPolicyOptions?.includeNumber"
|
|
/>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<ng-container *ngIf="passwordOptions.type === 'password'">
|
|
<div class="box">
|
|
<div class="box-content">
|
|
<div class="box-content-row box-content-row-slider" appBoxRow>
|
|
<label for="length">{{ "length" | i18n }}</label>
|
|
<input
|
|
id="length"
|
|
type="number"
|
|
min="5"
|
|
max="128"
|
|
[(ngModel)]="passwordOptions.length"
|
|
(change)="savePasswordOptions()"
|
|
/>
|
|
<input
|
|
id="lengthRange"
|
|
type="range"
|
|
min="5"
|
|
max="128"
|
|
step="1"
|
|
[(ngModel)]="passwordOptions.length"
|
|
(change)="sliderChanged()"
|
|
(input)="sliderInput()"
|
|
attr.aria-label="{{ 'length' | i18n }}"
|
|
tabindex="-1"
|
|
/>
|
|
</div>
|
|
<div class="box-content-row box-content-row-checkbox" appBoxRow>
|
|
<label for="uppercase">A-Z</label>
|
|
<input
|
|
id="uppercase"
|
|
type="checkbox"
|
|
(change)="savePasswordOptions()"
|
|
attr.aria-label="{{ 'uppercase' | i18n }}"
|
|
[disabled]="enforcedPasswordPolicyOptions.useUppercase"
|
|
[(ngModel)]="passwordOptions.uppercase"
|
|
/>
|
|
</div>
|
|
<div class="box-content-row box-content-row-checkbox" appBoxRow>
|
|
<label for="lowercase">a-z</label>
|
|
<input
|
|
id="lowercase"
|
|
type="checkbox"
|
|
(change)="savePasswordOptions()"
|
|
attr.aria-label="{{ 'lowercase' | i18n }}"
|
|
[disabled]="enforcedPasswordPolicyOptions.useLowercase"
|
|
[(ngModel)]="passwordOptions.lowercase"
|
|
/>
|
|
</div>
|
|
<div class="box-content-row box-content-row-checkbox" appBoxRow>
|
|
<label for="numbers">0-9</label>
|
|
<input
|
|
id="numbers"
|
|
type="checkbox"
|
|
(change)="savePasswordOptions()"
|
|
attr.aria-label="{{ 'numbers' | i18n }}"
|
|
[disabled]="enforcedPasswordPolicyOptions.useNumbers"
|
|
[(ngModel)]="passwordOptions.number"
|
|
/>
|
|
</div>
|
|
<div class="box-content-row box-content-row-checkbox" appBoxRow>
|
|
<label for="special">!@#$%^&*</label>
|
|
<input
|
|
id="special"
|
|
type="checkbox"
|
|
(change)="savePasswordOptions()"
|
|
attr.aria-label="{{ 'specialCharacters' | i18n }}"
|
|
[disabled]="enforcedPasswordPolicyOptions.useSpecial"
|
|
[(ngModel)]="passwordOptions.special"
|
|
/>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="box">
|
|
<div class="box-content">
|
|
<div class="box-content-row box-content-row-input" appBoxRow>
|
|
<label for="min-number">{{ "minNumbers" | i18n }}</label>
|
|
<input
|
|
id="min-number"
|
|
type="number"
|
|
min="0"
|
|
max="9"
|
|
(change)="savePasswordOptions()"
|
|
[(ngModel)]="passwordOptions.minNumber"
|
|
/>
|
|
</div>
|
|
<div class="box-content-row box-content-row-input" appBoxRow>
|
|
<label for="min-special">{{ "minSpecial" | i18n }}</label>
|
|
<input
|
|
id="min-special"
|
|
type="number"
|
|
min="0"
|
|
max="9"
|
|
(change)="savePasswordOptions()"
|
|
[(ngModel)]="passwordOptions.minSpecial"
|
|
/>
|
|
</div>
|
|
<div class="box-content-row box-content-row-checkbox" appBoxRow>
|
|
<label for="ambiguous">{{ "avoidAmbChar" | i18n }}</label>
|
|
<input
|
|
id="ambiguous"
|
|
type="checkbox"
|
|
(change)="savePasswordOptions()"
|
|
[(ngModel)]="avoidAmbiguous"
|
|
/>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</ng-container>
|
|
<div class="box list">
|
|
<div class="box-content single-line">
|
|
<a class="box-content-row box-content-row-flex" routerLink="/generator-history">
|
|
<div class="row-main">{{ "passwordHistory" | i18n }}</div>
|
|
<i class="bwi bwi-angle-right bwi-lg row-sub-icon" aria-hidden="true"></i>
|
|
</a>
|
|
</div>
|
|
</div>
|
|
</ng-container>
|
|
<ng-container *ngIf="type === 'username'">
|
|
<div class="box">
|
|
<h2 class="box-header">
|
|
{{ "options" | i18n }}
|
|
</h2>
|
|
<div class="box-content">
|
|
<div class="box-content-row">
|
|
<label class="radio-header">
|
|
{{ "usernameType" | i18n }}
|
|
<a
|
|
href="https://bitwarden.com/help/generator/#username-types"
|
|
target="_blank"
|
|
rel="noopener"
|
|
appA11yTitle="{{ 'learnMore' | i18n }}"
|
|
>
|
|
<i class="bwi bwi-question-circle" aria-hidden="true"></i>
|
|
</a>
|
|
</label>
|
|
<div
|
|
class="radio-group align-start text-default"
|
|
appBoxRow
|
|
*ngFor="let o of usernameTypeOptions"
|
|
>
|
|
<input
|
|
type="radio"
|
|
[(ngModel)]="usernameOptions.type"
|
|
name="Type_{{ o.value }}"
|
|
id="type_{{ o.value }}"
|
|
[value]="o.value"
|
|
(change)="saveUsernameOptions()"
|
|
[checked]="usernameOptions.type === o.value"
|
|
/>
|
|
<label for="type_{{ o.value }}">
|
|
{{ o.name }}
|
|
<div class="small text-muted" *ngIf="o.desc">{{ o.desc }}</div>
|
|
</label>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="box" *ngIf="usernameOptions.type === 'forwarded'">
|
|
<div class="box-content">
|
|
<div class="box-content-row">
|
|
<label class="radio-header">{{ "service" | i18n }}</label>
|
|
<div class="radio-group text-default" appBoxRow *ngFor="let o of forwardOptions">
|
|
<input
|
|
type="radio"
|
|
[(ngModel)]="usernameOptions.forwardedService"
|
|
name="ForwardType_{{ o.value }}"
|
|
id="forwardtype_{{ o.value }}"
|
|
[value]="o.value"
|
|
(change)="saveUsernameOptions()"
|
|
[checked]="usernameOptions.forwardedService === o.value"
|
|
/>
|
|
<label for="forwardtype_{{ o.value }}">
|
|
{{ o.name }}
|
|
</label>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="box" *ngIf="usernameOptions.type === 'subaddress'">
|
|
<div class="box-content">
|
|
<div class="box-content-row" appBoxRow>
|
|
<label for="subaddress-email">{{ "emailAddress" | i18n }}</label>
|
|
<input
|
|
id="subaddress-email"
|
|
type="text"
|
|
name="SubaddressEmail"
|
|
[(ngModel)]="usernameOptions.subaddressEmail"
|
|
(blur)="saveUsernameOptions()"
|
|
/>
|
|
</div>
|
|
<div class="box-content-row" *ngIf="subaddressOptions.length > 1">
|
|
<label class="radio-header">{{ "type" | i18n }}</label>
|
|
<div class="radio-group text-default" appBoxRow *ngFor="let o of subaddressOptions">
|
|
<input
|
|
type="radio"
|
|
[(ngModel)]="usernameOptions.subaddressType"
|
|
name="SubaddressType_{{ o.value }}"
|
|
id="subaddresstype_{{ o.value }}"
|
|
[value]="o.value"
|
|
(change)="saveUsernameOptions()"
|
|
[checked]="usernameOptions.subaddressType === o.value"
|
|
/>
|
|
<label for="subaddresstype_{{ o.value }}">
|
|
{{ o.name }}
|
|
</label>
|
|
</div>
|
|
</div>
|
|
<div class="box-content-row" appBoxRow *ngIf="usernameWebsite">
|
|
<label for="subaddress-website">{{ "website" | i18n }}</label>
|
|
<input
|
|
id="subaddress-website"
|
|
type="text"
|
|
name="SubaddressWebsite"
|
|
[value]="usernameOptions.website"
|
|
disabled
|
|
readonly
|
|
/>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="box" *ngIf="usernameOptions.type === 'catchall'">
|
|
<div class="box-content">
|
|
<div class="box-content-row" appBoxRow>
|
|
<label for="catchall-domain">{{ "domainName" | i18n }}</label>
|
|
<input
|
|
id="catchall-domain"
|
|
type="text"
|
|
name="CatchallDomain"
|
|
[(ngModel)]="usernameOptions.catchallDomain"
|
|
(blur)="saveUsernameOptions()"
|
|
/>
|
|
</div>
|
|
<div class="box-content-row" *ngIf="catchallOptions.length > 1">
|
|
<label class="radio-header">{{ "type" | i18n }}</label>
|
|
<div class="radio-group text-default" appBoxRow *ngFor="let o of catchallOptions">
|
|
<input
|
|
type="radio"
|
|
[(ngModel)]="usernameOptions.catchallType"
|
|
name="CatchallType_{{ o.value }}"
|
|
id="catchalltype_{{ o.value }}"
|
|
[value]="o.value"
|
|
(change)="saveUsernameOptions()"
|
|
[checked]="usernameOptions.catchallType === o.value"
|
|
/>
|
|
<label for="catchalltype_{{ o.value }}">
|
|
{{ o.name }}
|
|
</label>
|
|
</div>
|
|
</div>
|
|
<div class="box-content-row" appBoxRow *ngIf="usernameWebsite">
|
|
<label for="catchall-website">{{ "website" | i18n }}</label>
|
|
<input
|
|
id="catchall-website"
|
|
type="text"
|
|
name="CatchallWebsite"
|
|
[value]="usernameOptions.website"
|
|
disabled
|
|
readonly
|
|
/>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="box" *ngIf="usernameOptions.type === 'word'">
|
|
<div class="box-content">
|
|
<div class="box-content-row box-content-row-checkbox" appBoxRow>
|
|
<label for="capitalize">{{ "capitalize" | i18n }}</label>
|
|
<input
|
|
id="capitalize"
|
|
type="checkbox"
|
|
(change)="saveUsernameOptions()"
|
|
[(ngModel)]="usernameOptions.wordCapitalize"
|
|
/>
|
|
</div>
|
|
<div class="box-content-row box-content-row-checkbox" appBoxRow>
|
|
<label for="include-number">{{ "includeNumber" | i18n }}</label>
|
|
<input
|
|
id="include-number"
|
|
type="checkbox"
|
|
(change)="saveUsernameOptions()"
|
|
[(ngModel)]="usernameOptions.wordIncludeNumber"
|
|
/>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</ng-container>
|
|
</content>
|