mirror of
https://github.com/bitwarden/browser
synced 2026-02-18 10:23:52 +00:00
Merge remote-tracking branch 'origin/main' into playwright
This commit is contained in:
@@ -8,15 +8,18 @@ import {
|
||||
Output,
|
||||
SimpleChanges,
|
||||
} from "@angular/core";
|
||||
import { FormBuilder } from "@angular/forms";
|
||||
import { FormBuilder, ReactiveFormsModule } from "@angular/forms";
|
||||
import { map, ReplaySubject, skip, Subject, takeUntil, withLatestFrom } from "rxjs";
|
||||
|
||||
import { JslibModule } from "@bitwarden/angular/jslib.module";
|
||||
import { Account } from "@bitwarden/common/auth/abstractions/account.service";
|
||||
import { FormFieldModule } from "@bitwarden/components";
|
||||
import {
|
||||
CatchallGenerationOptions,
|
||||
CredentialGeneratorService,
|
||||
BuiltIn,
|
||||
} from "@bitwarden/generator-core";
|
||||
import { I18nPipe } from "@bitwarden/ui-common";
|
||||
|
||||
/** Options group for catchall emails */
|
||||
// FIXME(https://bitwarden.atlassian.net/browse/CL-764): Migrate to OnPush
|
||||
@@ -24,7 +27,7 @@ import {
|
||||
@Component({
|
||||
selector: "tools-catchall-settings",
|
||||
templateUrl: "catchall-settings.component.html",
|
||||
standalone: false,
|
||||
imports: [ReactiveFormsModule, FormFieldModule, JslibModule, I18nPipe],
|
||||
})
|
||||
export class CatchallSettingsComponent implements OnInit, OnDestroy, OnChanges {
|
||||
/** Instantiates the component
|
||||
|
||||
@@ -1,8 +1,11 @@
|
||||
<bit-dialog #dialog background="alt">
|
||||
<span bitDialogTitle>{{ "generatorHistory" | i18n }}</span>
|
||||
<ng-container bitDialogContent>
|
||||
<bit-empty-credential-history *ngIf="!(hasHistory$ | async)" style="display: contents" />
|
||||
<bit-credential-generator-history [account]="account$ | async" *ngIf="hasHistory$ | async" />
|
||||
@if (hasHistory$ | async) {
|
||||
<bit-credential-generator-history [account]="account$ | async" />
|
||||
} @else {
|
||||
<bit-empty-credential-history style="display: contents" />
|
||||
}
|
||||
</ng-container>
|
||||
<ng-container bitDialogFooter>
|
||||
<button
|
||||
|
||||
@@ -1,22 +1,24 @@
|
||||
<bit-item *ngFor="let credential of credentials$ | async">
|
||||
<bit-item-content>
|
||||
<bit-color-password class="tw-font-mono" [password]="credential.credential" />
|
||||
<div slot="secondary">
|
||||
{{ credential.generationDate | date: "medium" }}
|
||||
</div>
|
||||
</bit-item-content>
|
||||
<ng-container slot="end">
|
||||
<bit-item-action>
|
||||
<button
|
||||
type="button"
|
||||
bitIconButton="bwi-clone"
|
||||
[appCopyClick]="credential.credential"
|
||||
[valueLabel]="getGeneratedValueText(credential)"
|
||||
[label]="getCopyText(credential)"
|
||||
showToast
|
||||
>
|
||||
{{ getCopyText(credential) }}
|
||||
</button>
|
||||
</bit-item-action>
|
||||
</ng-container>
|
||||
</bit-item>
|
||||
@for (credential of credentials$ | async; track credential) {
|
||||
<bit-item>
|
||||
<bit-item-content>
|
||||
<bit-color-password class="tw-font-mono" [password]="credential.credential" />
|
||||
<div slot="secondary">
|
||||
{{ credential.generationDate | date: "medium" }}
|
||||
</div>
|
||||
</bit-item-content>
|
||||
<ng-container slot="end">
|
||||
<bit-item-action>
|
||||
<button
|
||||
type="button"
|
||||
bitIconButton="bwi-clone"
|
||||
[appCopyClick]="credential.credential"
|
||||
[valueLabel]="getGeneratedValueText(credential)"
|
||||
[label]="getCopyText(credential)"
|
||||
showToast
|
||||
>
|
||||
{{ getCopyText(credential) }}
|
||||
</button>
|
||||
</bit-item-action>
|
||||
</ng-container>
|
||||
</bit-item>
|
||||
}
|
||||
|
||||
@@ -23,7 +23,6 @@ import {
|
||||
import { AlgorithmsByType, CredentialGeneratorService } from "@bitwarden/generator-core";
|
||||
import { GeneratedCredential, GeneratorHistoryService } from "@bitwarden/generator-history";
|
||||
|
||||
import { GeneratorModule } from "./generator.module";
|
||||
import { translate } from "./util";
|
||||
|
||||
// FIXME(https://bitwarden.atlassian.net/browse/CL-764): Migrate to OnPush
|
||||
@@ -32,13 +31,12 @@ import { translate } from "./util";
|
||||
selector: "bit-credential-generator-history",
|
||||
templateUrl: "credential-generator-history.component.html",
|
||||
imports: [
|
||||
ColorPasswordModule,
|
||||
CommonModule,
|
||||
ColorPasswordModule,
|
||||
IconButtonModule,
|
||||
NoItemsModule,
|
||||
JslibModule,
|
||||
ItemModule,
|
||||
GeneratorModule,
|
||||
],
|
||||
})
|
||||
export class CredentialGeneratorHistoryComponent implements OnChanges, OnInit, OnDestroy {
|
||||
|
||||
@@ -6,9 +6,11 @@
|
||||
(selectedChange)="onRootChanged({ nav: $event })"
|
||||
attr.aria-label="{{ 'type' | i18n }}"
|
||||
>
|
||||
<bit-toggle *ngFor="let option of rootOptions$ | async" [value]="option.value">
|
||||
{{ option.label }}
|
||||
</bit-toggle>
|
||||
@for (option of rootOptions$ | async; track option) {
|
||||
<bit-toggle [value]="option.value">
|
||||
{{ option.label }}
|
||||
</bit-toggle>
|
||||
}
|
||||
</bit-toggle-group>
|
||||
|
||||
<nudge-generator-spotlight></nudge-generator-spotlight>
|
||||
@@ -40,69 +42,80 @@
|
||||
></button>
|
||||
</div>
|
||||
</bit-card>
|
||||
<tools-password-settings
|
||||
class="tw-mt-6"
|
||||
*ngIf="(showAlgorithm$ | async)?.id === Algorithm.password"
|
||||
[account]="account$ | async"
|
||||
(onUpdated)="generate('password settings')"
|
||||
/>
|
||||
<tools-passphrase-settings
|
||||
class="tw-mt-6"
|
||||
*ngIf="(showAlgorithm$ | async)?.id === Algorithm.passphrase"
|
||||
[account]="account$ | async"
|
||||
(onUpdated)="generate('passphrase settings')"
|
||||
/>
|
||||
<bit-section *ngIf="(category$ | async) !== 'password'">
|
||||
<bit-section-header>
|
||||
<h2 bitTypography="h6">{{ "options" | i18n }}</h2>
|
||||
</bit-section-header>
|
||||
<div class="tw-mb-4">
|
||||
<bit-card>
|
||||
<form [formGroup]="username" class="tw-container">
|
||||
<bit-form-field>
|
||||
<bit-label>{{ "type" | i18n }}</bit-label>
|
||||
<bit-select
|
||||
[items]="usernameOptions$ | async"
|
||||
formControlName="nav"
|
||||
data-testid="username-type"
|
||||
>
|
||||
</bit-select>
|
||||
<bit-hint *ngIf="!!(credentialTypeHint$ | async)">{{
|
||||
credentialTypeHint$ | async
|
||||
}}</bit-hint>
|
||||
</bit-form-field>
|
||||
</form>
|
||||
<form *ngIf="showForwarder$ | async" [formGroup]="forwarder" class="tw-container">
|
||||
<bit-form-field>
|
||||
<bit-label>{{ "service" | i18n }}</bit-label>
|
||||
<bit-select
|
||||
[items]="forwarderOptions$ | async"
|
||||
formControlName="nav"
|
||||
data-testid="email-forwarding-service"
|
||||
>
|
||||
</bit-select>
|
||||
</bit-form-field>
|
||||
</form>
|
||||
<tools-catchall-settings
|
||||
*ngIf="(showAlgorithm$ | async)?.id === Algorithm.catchall"
|
||||
[account]="account$ | async"
|
||||
(onUpdated)="generate('catchall settings')"
|
||||
/>
|
||||
<tools-forwarder-settings
|
||||
*ngIf="!!(forwarderId$ | async)"
|
||||
[account]="account$ | async"
|
||||
[forwarder]="forwarderId$ | async"
|
||||
/>
|
||||
<tools-subaddress-settings
|
||||
*ngIf="(showAlgorithm$ | async)?.id === Algorithm.plusAddress"
|
||||
[account]="account$ | async"
|
||||
(onUpdated)="generate('subaddress settings')"
|
||||
/>
|
||||
<tools-username-settings
|
||||
*ngIf="(showAlgorithm$ | async)?.id === Algorithm.username"
|
||||
[account]="account$ | async"
|
||||
(onUpdated)="generate('username settings')"
|
||||
/>
|
||||
</bit-card>
|
||||
</div>
|
||||
</bit-section>
|
||||
@let showAlgorithm = showAlgorithm$ | async;
|
||||
@let account = account$ | async;
|
||||
@switch (showAlgorithm?.id) {
|
||||
@case (Algorithm.password) {
|
||||
<tools-password-settings
|
||||
class="tw-mt-6"
|
||||
[account]="account"
|
||||
(onUpdated)="generate('password settings')"
|
||||
/>
|
||||
}
|
||||
@case (Algorithm.passphrase) {
|
||||
<tools-passphrase-settings
|
||||
class="tw-mt-6"
|
||||
[account]="account"
|
||||
(onUpdated)="generate('passphrase settings')"
|
||||
/>
|
||||
}
|
||||
}
|
||||
@if ((category$ | async) !== "password") {
|
||||
<bit-section>
|
||||
<bit-section-header>
|
||||
<h2 bitTypography="h6">{{ "options" | i18n }}</h2>
|
||||
</bit-section-header>
|
||||
<div class="tw-mb-4">
|
||||
<bit-card>
|
||||
<form [formGroup]="username" class="tw-container">
|
||||
<bit-form-field>
|
||||
<bit-label>{{ "type" | i18n }}</bit-label>
|
||||
<bit-select
|
||||
[items]="usernameOptions$ | async"
|
||||
formControlName="nav"
|
||||
data-testid="username-type"
|
||||
>
|
||||
</bit-select>
|
||||
@if (credentialTypeHint$ | async) {
|
||||
<bit-hint>{{ credentialTypeHint$ | async }}</bit-hint>
|
||||
}
|
||||
</bit-form-field>
|
||||
</form>
|
||||
@if (showForwarder$ | async) {
|
||||
<form [formGroup]="forwarder" class="tw-container">
|
||||
<bit-form-field>
|
||||
<bit-label>{{ "service" | i18n }}</bit-label>
|
||||
<bit-select
|
||||
[items]="forwarderOptions$ | async"
|
||||
formControlName="nav"
|
||||
data-testid="email-forwarding-service"
|
||||
>
|
||||
</bit-select>
|
||||
</bit-form-field>
|
||||
</form>
|
||||
}
|
||||
@if (showAlgorithm?.id === Algorithm.catchall) {
|
||||
<tools-catchall-settings
|
||||
[account]="account"
|
||||
(onUpdated)="generate('catchall settings')"
|
||||
/>
|
||||
}
|
||||
@if (forwarderId$ | async; as forwarderId) {
|
||||
<tools-forwarder-settings [account]="account" [forwarder]="forwarderId" />
|
||||
}
|
||||
@if (showAlgorithm?.id === Algorithm.plusAddress) {
|
||||
<tools-subaddress-settings
|
||||
[account]="account"
|
||||
(onUpdated)="generate('subaddress settings')"
|
||||
/>
|
||||
}
|
||||
@if (showAlgorithm?.id === Algorithm.username) {
|
||||
<tools-username-settings
|
||||
[account]="account"
|
||||
(onUpdated)="generate('username settings')"
|
||||
/>
|
||||
}
|
||||
</bit-card>
|
||||
</div>
|
||||
</bit-section>
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { LiveAnnouncer } from "@angular/cdk/a11y";
|
||||
import { AsyncPipe } from "@angular/common";
|
||||
import {
|
||||
Component,
|
||||
EventEmitter,
|
||||
@@ -10,7 +11,7 @@ import {
|
||||
Output,
|
||||
SimpleChanges,
|
||||
} from "@angular/core";
|
||||
import { FormBuilder } from "@angular/forms";
|
||||
import { FormBuilder, ReactiveFormsModule } from "@angular/forms";
|
||||
import {
|
||||
BehaviorSubject,
|
||||
catchError,
|
||||
@@ -27,6 +28,7 @@ import {
|
||||
withLatestFrom,
|
||||
} from "rxjs";
|
||||
|
||||
import { JslibModule } from "@bitwarden/angular/jslib.module";
|
||||
import { Account, AccountService } from "@bitwarden/common/auth/abstractions/account.service";
|
||||
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
||||
import { LogService } from "@bitwarden/common/platform/abstractions/log.service";
|
||||
@@ -37,7 +39,23 @@ import {
|
||||
ifEnabledSemanticLoggerProvider,
|
||||
} from "@bitwarden/common/tools/log";
|
||||
import { UserId } from "@bitwarden/common/types/guid";
|
||||
import { ToastService, Option } from "@bitwarden/components";
|
||||
import {
|
||||
ToastService,
|
||||
Option,
|
||||
BaseCardDirective,
|
||||
CardComponent,
|
||||
ColorPasswordComponent,
|
||||
AriaDisableDirective,
|
||||
TooltipDirective,
|
||||
BitIconButtonComponent,
|
||||
CopyClickDirective,
|
||||
SectionComponent,
|
||||
SectionHeaderComponent,
|
||||
ToggleGroupModule,
|
||||
TypographyModule,
|
||||
FormFieldModule,
|
||||
SelectModule,
|
||||
} from "@bitwarden/components";
|
||||
import {
|
||||
CredentialType,
|
||||
CredentialGeneratorService,
|
||||
@@ -55,7 +73,15 @@ import {
|
||||
Type,
|
||||
} from "@bitwarden/generator-core";
|
||||
import { GeneratorHistoryService } from "@bitwarden/generator-history";
|
||||
import { I18nPipe } from "@bitwarden/ui-common";
|
||||
|
||||
import { CatchallSettingsComponent } from "./catchall-settings.component";
|
||||
import { ForwarderSettingsComponent } from "./forwarder-settings.component";
|
||||
import { NudgeGeneratorSpotlightComponent } from "./nudge-generator-spotlight.component";
|
||||
import { PassphraseSettingsComponent } from "./passphrase-settings.component";
|
||||
import { PasswordSettingsComponent } from "./password-settings.component";
|
||||
import { SubaddressSettingsComponent } from "./subaddress-settings.component";
|
||||
import { UsernameSettingsComponent } from "./username-settings.component";
|
||||
import { translate } from "./util";
|
||||
|
||||
// constants used to identify navigation selections that are not
|
||||
@@ -69,7 +95,32 @@ const NONE_SELECTED = "none";
|
||||
@Component({
|
||||
selector: "tools-credential-generator",
|
||||
templateUrl: "credential-generator.component.html",
|
||||
standalone: false,
|
||||
imports: [
|
||||
ToggleGroupModule,
|
||||
NudgeGeneratorSpotlightComponent,
|
||||
BaseCardDirective,
|
||||
CardComponent,
|
||||
ColorPasswordComponent,
|
||||
AriaDisableDirective,
|
||||
TooltipDirective,
|
||||
BitIconButtonComponent,
|
||||
CopyClickDirective,
|
||||
PasswordSettingsComponent,
|
||||
PassphraseSettingsComponent,
|
||||
SectionComponent,
|
||||
SectionHeaderComponent,
|
||||
TypographyModule,
|
||||
ReactiveFormsModule,
|
||||
FormFieldModule,
|
||||
SelectModule,
|
||||
CatchallSettingsComponent,
|
||||
ForwarderSettingsComponent,
|
||||
SubaddressSettingsComponent,
|
||||
UsernameSettingsComponent,
|
||||
AsyncPipe,
|
||||
JslibModule,
|
||||
I18nPipe,
|
||||
],
|
||||
})
|
||||
export class CredentialGeneratorComponent implements OnInit, OnChanges, OnDestroy {
|
||||
private readonly destroyed = new Subject<void>();
|
||||
|
||||
@@ -1,28 +1,34 @@
|
||||
<form [formGroup]="settings" class="tw-container">
|
||||
<bit-form-field *ngIf="displayDomain">
|
||||
<bit-label>{{ "forwarderDomainName" | i18n }}</bit-label>
|
||||
<input
|
||||
bitInput
|
||||
formControlName="domain"
|
||||
type="text"
|
||||
placeholder="example.com"
|
||||
(change)="save('domain')"
|
||||
/>
|
||||
<bit-hint>{{ "forwarderDomainNameHint" | i18n }}</bit-hint>
|
||||
</bit-form-field>
|
||||
<bit-form-field *ngIf="displayToken">
|
||||
<bit-label>{{ "apiKey" | i18n }}</bit-label>
|
||||
<input bitInput formControlName="token" type="password" (change)="save('password')" />
|
||||
<button
|
||||
type="button"
|
||||
bitIconButton
|
||||
bitSuffix
|
||||
bitPasswordInputToggle
|
||||
(change)="save('token')"
|
||||
></button>
|
||||
</bit-form-field>
|
||||
<bit-form-field *ngIf="displayBaseUrl" disableMargin>
|
||||
<bit-label>{{ "selfHostBaseUrl" | i18n }}</bit-label>
|
||||
<input bitInput formControlName="baseUrl" type="text" (change)="save('baseUrl')" />
|
||||
</bit-form-field>
|
||||
@if (displayDomain) {
|
||||
<bit-form-field>
|
||||
<bit-label>{{ "forwarderDomainName" | i18n }}</bit-label>
|
||||
<input
|
||||
bitInput
|
||||
formControlName="domain"
|
||||
type="text"
|
||||
placeholder="example.com"
|
||||
(change)="save('domain')"
|
||||
/>
|
||||
<bit-hint>{{ "forwarderDomainNameHint" | i18n }}</bit-hint>
|
||||
</bit-form-field>
|
||||
}
|
||||
@if (displayToken) {
|
||||
<bit-form-field>
|
||||
<bit-label>{{ "apiKey" | i18n }}</bit-label>
|
||||
<input bitInput formControlName="token" type="password" (change)="save('password')" />
|
||||
<button
|
||||
type="button"
|
||||
bitIconButton
|
||||
bitSuffix
|
||||
bitPasswordInputToggle
|
||||
(change)="save('token')"
|
||||
></button>
|
||||
</bit-form-field>
|
||||
}
|
||||
@if (displayBaseUrl) {
|
||||
<bit-form-field disableMargin>
|
||||
<bit-label>{{ "selfHostBaseUrl" | i18n }}</bit-label>
|
||||
<input bitInput formControlName="baseUrl" type="text" (change)="save('baseUrl')" />
|
||||
</bit-form-field>
|
||||
}
|
||||
</form>
|
||||
|
||||
@@ -8,16 +8,24 @@ import {
|
||||
Output,
|
||||
SimpleChanges,
|
||||
} from "@angular/core";
|
||||
import { FormBuilder } from "@angular/forms";
|
||||
import { FormBuilder, ReactiveFormsModule } from "@angular/forms";
|
||||
import { map, ReplaySubject, skip, Subject, switchAll, takeUntil, withLatestFrom } from "rxjs";
|
||||
|
||||
import { JslibModule } from "@bitwarden/angular/jslib.module";
|
||||
import { Account } from "@bitwarden/common/auth/abstractions/account.service";
|
||||
import { VendorId } from "@bitwarden/common/tools/extension";
|
||||
import {
|
||||
FormFieldModule,
|
||||
AriaDisableDirective,
|
||||
TooltipDirective,
|
||||
BitIconButtonComponent,
|
||||
} from "@bitwarden/components";
|
||||
import {
|
||||
CredentialGeneratorService,
|
||||
ForwarderOptions,
|
||||
GeneratorMetadata,
|
||||
} from "@bitwarden/generator-core";
|
||||
import { I18nPipe } from "@bitwarden/ui-common";
|
||||
|
||||
const Controls = Object.freeze({
|
||||
domain: "domain",
|
||||
@@ -31,7 +39,15 @@ const Controls = Object.freeze({
|
||||
@Component({
|
||||
selector: "tools-forwarder-settings",
|
||||
templateUrl: "forwarder-settings.component.html",
|
||||
standalone: false,
|
||||
imports: [
|
||||
ReactiveFormsModule,
|
||||
FormFieldModule,
|
||||
AriaDisableDirective,
|
||||
TooltipDirective,
|
||||
BitIconButtonComponent,
|
||||
JslibModule,
|
||||
I18nPipe,
|
||||
],
|
||||
})
|
||||
export class ForwarderSettingsComponent implements OnInit, OnChanges, OnDestroy {
|
||||
/** Instantiates the component
|
||||
|
||||
@@ -1,67 +1,13 @@
|
||||
import { CommonModule } from "@angular/common";
|
||||
import { NgModule } from "@angular/core";
|
||||
import { ReactiveFormsModule } from "@angular/forms";
|
||||
|
||||
import { JslibModule } from "@bitwarden/angular/jslib.module";
|
||||
import {
|
||||
CardComponent,
|
||||
ColorPasswordModule,
|
||||
CheckboxModule,
|
||||
FormFieldModule,
|
||||
IconButtonModule,
|
||||
InputModule,
|
||||
ItemModule,
|
||||
SectionComponent,
|
||||
SectionHeaderComponent,
|
||||
SelectModule,
|
||||
ToggleGroupModule,
|
||||
TypographyModule,
|
||||
} from "@bitwarden/components";
|
||||
|
||||
import { CatchallSettingsComponent } from "./catchall-settings.component";
|
||||
import { CredentialGeneratorComponent } from "./credential-generator.component";
|
||||
import { ForwarderSettingsComponent } from "./forwarder-settings.component";
|
||||
import { GeneratorServicesModule } from "./generator-services.module";
|
||||
import { NudgeGeneratorSpotlightComponent } from "./nudge-generator-spotlight.component";
|
||||
import { PassphraseSettingsComponent } from "./passphrase-settings.component";
|
||||
import { PasswordGeneratorComponent } from "./password-generator.component";
|
||||
import { PasswordSettingsComponent } from "./password-settings.component";
|
||||
import { SubaddressSettingsComponent } from "./subaddress-settings.component";
|
||||
import { UsernameGeneratorComponent } from "./username-generator.component";
|
||||
import { UsernameSettingsComponent } from "./username-settings.component";
|
||||
|
||||
/** Shared module containing generator component dependencies */
|
||||
/** @deprecated Use individual components instead. */
|
||||
@NgModule({
|
||||
imports: [
|
||||
CardComponent,
|
||||
ColorPasswordModule,
|
||||
CheckboxModule,
|
||||
CommonModule,
|
||||
FormFieldModule,
|
||||
GeneratorServicesModule,
|
||||
IconButtonModule,
|
||||
InputModule,
|
||||
ItemModule,
|
||||
JslibModule,
|
||||
ReactiveFormsModule,
|
||||
SectionComponent,
|
||||
SectionHeaderComponent,
|
||||
SelectModule,
|
||||
ToggleGroupModule,
|
||||
TypographyModule,
|
||||
NudgeGeneratorSpotlightComponent,
|
||||
],
|
||||
declarations: [
|
||||
CatchallSettingsComponent,
|
||||
CredentialGeneratorComponent,
|
||||
ForwarderSettingsComponent,
|
||||
SubaddressSettingsComponent,
|
||||
PasswordGeneratorComponent,
|
||||
PassphraseSettingsComponent,
|
||||
PasswordSettingsComponent,
|
||||
UsernameGeneratorComponent,
|
||||
UsernameSettingsComponent,
|
||||
],
|
||||
imports: [CredentialGeneratorComponent, PasswordGeneratorComponent, UsernameGeneratorComponent],
|
||||
exports: [CredentialGeneratorComponent, PasswordGeneratorComponent, UsernameGeneratorComponent],
|
||||
})
|
||||
export class GeneratorModule {
|
||||
|
||||
@@ -1,5 +1,15 @@
|
||||
/**
|
||||
* This file contains the public interface for the generator components library.
|
||||
*
|
||||
* Be mindful of what you export here, as those components should be considered stable
|
||||
* and part of the public API contract.
|
||||
*/
|
||||
|
||||
export { CredentialGeneratorComponent } from "./credential-generator.component";
|
||||
export { CredentialGeneratorHistoryComponent } from "./credential-generator-history.component";
|
||||
export { CredentialGeneratorHistoryDialogComponent } from "./credential-generator-history-dialog.component";
|
||||
export { EmptyCredentialHistoryComponent } from "./empty-credential-history.component";
|
||||
export { GeneratorModule } from "./generator.module";
|
||||
export { GeneratorServicesModule, SYSTEM_SERVICE_PROVIDER } from "./generator-services.module";
|
||||
export { PasswordGeneratorComponent } from "./password-generator.component";
|
||||
export { UsernameGeneratorComponent } from "./username-generator.component";
|
||||
|
||||
@@ -1,16 +1,18 @@
|
||||
<div class="tw-mb-4" *ngIf="showGeneratorSpotlight$ | async">
|
||||
<bit-spotlight
|
||||
[title]="'generatorNudgeTitle' | i18n"
|
||||
(onDismiss)="dismissGeneratorSpotlight(NudgeType.GeneratorNudgeStatus)"
|
||||
>
|
||||
<p class="tw-text-main tw-mb-0" bitTypography="body2">
|
||||
<span class="tw-sr-only">
|
||||
{{ "generatorNudgeBodyAria" | i18n }}
|
||||
</span>
|
||||
<span aria-hidden="true">
|
||||
{{ "generatorNudgeBodyOne" | i18n }} <i class="bwi bwi-generate"></i>
|
||||
{{ "generatorNudgeBodyTwo" | i18n }}
|
||||
</span>
|
||||
</p>
|
||||
</bit-spotlight>
|
||||
</div>
|
||||
@if (showGeneratorSpotlight$ | async) {
|
||||
<div class="tw-mb-4">
|
||||
<bit-spotlight
|
||||
[title]="'generatorNudgeTitle' | i18n"
|
||||
(onDismiss)="dismissGeneratorSpotlight(NudgeType.GeneratorNudgeStatus)"
|
||||
>
|
||||
<p class="tw-text-main tw-mb-0" bitTypography="body2">
|
||||
<span class="tw-sr-only">
|
||||
{{ "generatorNudgeBodyAria" | i18n }}
|
||||
</span>
|
||||
<span aria-hidden="true">
|
||||
{{ "generatorNudgeBodyOne" | i18n }} <i class="bwi bwi-generate"></i>
|
||||
{{ "generatorNudgeBodyTwo" | i18n }}
|
||||
</span>
|
||||
</p>
|
||||
</bit-spotlight>
|
||||
</div>
|
||||
}
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
<bit-section [disableMargin]="disableMargin">
|
||||
<bit-section-header *ngIf="showHeader">
|
||||
<h6 bitTypography="h6">{{ "options" | i18n }}</h6>
|
||||
</bit-section-header>
|
||||
@if (showHeader) {
|
||||
<bit-section-header>
|
||||
<h6 bitTypography="h6">{{ "options" | i18n }}</h6>
|
||||
</bit-section-header>
|
||||
}
|
||||
<form [formGroup]="settings" class="tw-container">
|
||||
<div class="tw-mb-4">
|
||||
<bit-card>
|
||||
@@ -51,7 +53,9 @@
|
||||
/>
|
||||
<bit-label>{{ "includeNumber" | i18n }}</bit-label>
|
||||
</bit-form-control>
|
||||
<p *ngIf="policyInEffect" bitTypography="helper">{{ "generatorPolicyInEffect" | i18n }}</p>
|
||||
@if (policyInEffect) {
|
||||
<p bitTypography="helper">{{ "generatorPolicyInEffect" | i18n }}</p>
|
||||
}
|
||||
</bit-card>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { coerceBooleanProperty } from "@angular/cdk/coercion";
|
||||
import { AsyncPipe } from "@angular/common";
|
||||
import {
|
||||
OnInit,
|
||||
Input,
|
||||
@@ -9,9 +10,10 @@ import {
|
||||
SimpleChanges,
|
||||
OnChanges,
|
||||
} from "@angular/core";
|
||||
import { FormBuilder } from "@angular/forms";
|
||||
import { FormBuilder, ReactiveFormsModule } from "@angular/forms";
|
||||
import { skip, takeUntil, Subject, map, withLatestFrom, ReplaySubject, tap } from "rxjs";
|
||||
|
||||
import { JslibModule } from "@bitwarden/angular/jslib.module";
|
||||
import { Account } from "@bitwarden/common/auth/abstractions/account.service";
|
||||
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
||||
import { LogService } from "@bitwarden/common/platform/abstractions/log.service";
|
||||
@@ -20,11 +22,21 @@ import {
|
||||
disabledSemanticLoggerProvider,
|
||||
ifEnabledSemanticLoggerProvider,
|
||||
} from "@bitwarden/common/tools/log";
|
||||
import {
|
||||
SectionComponent,
|
||||
SectionHeaderComponent,
|
||||
BaseCardDirective,
|
||||
CardComponent,
|
||||
TypographyModule,
|
||||
FormFieldModule,
|
||||
CheckboxModule,
|
||||
} from "@bitwarden/components";
|
||||
import {
|
||||
CredentialGeneratorService,
|
||||
PassphraseGenerationOptions,
|
||||
BuiltIn,
|
||||
} from "@bitwarden/generator-core";
|
||||
import { I18nPipe } from "@bitwarden/ui-common";
|
||||
|
||||
const Controls = Object.freeze({
|
||||
numWords: "numWords",
|
||||
@@ -39,7 +51,19 @@ const Controls = Object.freeze({
|
||||
@Component({
|
||||
selector: "tools-passphrase-settings",
|
||||
templateUrl: "passphrase-settings.component.html",
|
||||
standalone: false,
|
||||
imports: [
|
||||
SectionComponent,
|
||||
SectionHeaderComponent,
|
||||
TypographyModule,
|
||||
ReactiveFormsModule,
|
||||
BaseCardDirective,
|
||||
CardComponent,
|
||||
FormFieldModule,
|
||||
CheckboxModule,
|
||||
AsyncPipe,
|
||||
JslibModule,
|
||||
I18nPipe,
|
||||
],
|
||||
})
|
||||
export class PassphraseSettingsComponent implements OnInit, OnChanges, OnDestroy {
|
||||
/** Instantiates the component
|
||||
|
||||
@@ -1,15 +1,18 @@
|
||||
<bit-toggle-group
|
||||
fullWidth
|
||||
class="tw-mb-4"
|
||||
[selected]="credentialType$ | async"
|
||||
(selectedChange)="onCredentialTypeChanged($event)"
|
||||
*ngIf="showCredentialTypes$ | async"
|
||||
attr.aria-label="{{ 'type' | i18n }}"
|
||||
>
|
||||
<bit-toggle *ngFor="let option of passwordOptions$ | async" [value]="option.value">
|
||||
{{ option.label }}
|
||||
</bit-toggle>
|
||||
</bit-toggle-group>
|
||||
@if (showCredentialTypes$ | async) {
|
||||
<bit-toggle-group
|
||||
fullWidth
|
||||
class="tw-mb-4"
|
||||
[selected]="credentialType$ | async"
|
||||
(selectedChange)="onCredentialTypeChanged($event)"
|
||||
attr.aria-label="{{ 'type' | i18n }}"
|
||||
>
|
||||
@for (option of passwordOptions$ | async; track option) {
|
||||
<bit-toggle [value]="option.value">
|
||||
{{ option.label }}
|
||||
</bit-toggle>
|
||||
}
|
||||
</bit-toggle-group>
|
||||
}
|
||||
<bit-card class="tw-flex tw-justify-between tw-mb-4">
|
||||
<div class="tw-grow tw-flex tw-items-center tw-min-w-0">
|
||||
<bit-color-password class="tw-font-mono" [password]="value$ | async"></bit-color-password>
|
||||
@@ -37,17 +40,19 @@
|
||||
></button>
|
||||
</div>
|
||||
</bit-card>
|
||||
<tools-password-settings
|
||||
class="tw-mt-6"
|
||||
*ngIf="(algorithm$ | async)?.id === Algorithm.password"
|
||||
[account]="account$ | async"
|
||||
[disableMargin]="disableMargin"
|
||||
(onUpdated)="generate('password settings')"
|
||||
/>
|
||||
<tools-passphrase-settings
|
||||
class="tw-mt-6"
|
||||
*ngIf="(algorithm$ | async)?.id === Algorithm.passphrase"
|
||||
[account]="account$ | async"
|
||||
(onUpdated)="generate('passphrase settings')"
|
||||
[disableMargin]="disableMargin"
|
||||
/>
|
||||
@if ((algorithm$ | async)?.id === Algorithm.password) {
|
||||
<tools-password-settings
|
||||
class="tw-mt-6"
|
||||
[account]="account$ | async"
|
||||
[disableMargin]="disableMargin"
|
||||
(onUpdated)="generate('password settings')"
|
||||
/>
|
||||
}
|
||||
@if ((algorithm$ | async)?.id === Algorithm.passphrase) {
|
||||
<tools-passphrase-settings
|
||||
class="tw-mt-6"
|
||||
[account]="account$ | async"
|
||||
(onUpdated)="generate('passphrase settings')"
|
||||
[disableMargin]="disableMargin"
|
||||
/>
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { LiveAnnouncer } from "@angular/cdk/a11y";
|
||||
import { coerceBooleanProperty } from "@angular/cdk/coercion";
|
||||
import { AsyncPipe } from "@angular/common";
|
||||
import {
|
||||
Component,
|
||||
EventEmitter,
|
||||
@@ -24,6 +25,7 @@ import {
|
||||
withLatestFrom,
|
||||
} from "rxjs";
|
||||
|
||||
import { JslibModule } from "@bitwarden/angular/jslib.module";
|
||||
import { Account, AccountService } from "@bitwarden/common/auth/abstractions/account.service";
|
||||
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
||||
import { LogService } from "@bitwarden/common/platform/abstractions/log.service";
|
||||
@@ -33,7 +35,18 @@ import {
|
||||
ifEnabledSemanticLoggerProvider,
|
||||
} from "@bitwarden/common/tools/log";
|
||||
import { UserId } from "@bitwarden/common/types/guid";
|
||||
import { ToastService, Option } from "@bitwarden/components";
|
||||
import {
|
||||
ToastService,
|
||||
Option,
|
||||
BaseCardDirective,
|
||||
CardComponent,
|
||||
ColorPasswordComponent,
|
||||
AriaDisableDirective,
|
||||
TooltipDirective,
|
||||
BitIconButtonComponent,
|
||||
CopyClickDirective,
|
||||
ToggleGroupModule,
|
||||
} from "@bitwarden/components";
|
||||
import {
|
||||
CredentialGeneratorService,
|
||||
GeneratedCredential,
|
||||
@@ -49,7 +62,10 @@ import {
|
||||
Profile,
|
||||
} from "@bitwarden/generator-core";
|
||||
import { GeneratorHistoryService } from "@bitwarden/generator-history";
|
||||
import { I18nPipe } from "@bitwarden/ui-common";
|
||||
|
||||
import { PassphraseSettingsComponent } from "./passphrase-settings.component";
|
||||
import { PasswordSettingsComponent } from "./password-settings.component";
|
||||
import { toAlgorithmInfo, translate } from "./util";
|
||||
|
||||
/** Options group for passwords */
|
||||
@@ -58,7 +74,21 @@ import { toAlgorithmInfo, translate } from "./util";
|
||||
@Component({
|
||||
selector: "tools-password-generator",
|
||||
templateUrl: "password-generator.component.html",
|
||||
standalone: false,
|
||||
imports: [
|
||||
ToggleGroupModule,
|
||||
BaseCardDirective,
|
||||
CardComponent,
|
||||
ColorPasswordComponent,
|
||||
AriaDisableDirective,
|
||||
TooltipDirective,
|
||||
BitIconButtonComponent,
|
||||
CopyClickDirective,
|
||||
PasswordSettingsComponent,
|
||||
PassphraseSettingsComponent,
|
||||
AsyncPipe,
|
||||
JslibModule,
|
||||
I18nPipe,
|
||||
],
|
||||
})
|
||||
export class PasswordGeneratorComponent implements OnInit, OnChanges, OnDestroy {
|
||||
constructor(
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
<bit-section [disableMargin]="disableMargin">
|
||||
<bit-section-header *ngIf="showHeader">
|
||||
<h2 bitTypography="h6">{{ "options" | i18n }}</h2>
|
||||
</bit-section-header>
|
||||
@if (showHeader) {
|
||||
<bit-section-header>
|
||||
<h2 bitTypography="h6">{{ "options" | i18n }}</h2>
|
||||
</bit-section-header>
|
||||
}
|
||||
<form [formGroup]="settings" class="tw-container">
|
||||
<div class="tw-mb-4">
|
||||
<bit-card>
|
||||
@@ -50,11 +52,7 @@
|
||||
<input bitCheckbox type="checkbox" formControlName="number" (change)="save('number')" />
|
||||
<bit-label>{{ "numbersLabel" | i18n }}</bit-label>
|
||||
</bit-form-control>
|
||||
<bit-form-control
|
||||
class="!tw-mb-0"
|
||||
attr.aria-description="{{ 'specialCharactersDescription' | i18n }}"
|
||||
title="{{ 'specialCharactersDescription' | i18n }}"
|
||||
>
|
||||
<bit-form-control class="!tw-mb-0" title="{{ 'specialCharactersDescription' | i18n }}">
|
||||
<input
|
||||
bitCheckbox
|
||||
type="checkbox"
|
||||
@@ -62,10 +60,15 @@
|
||||
(change)="save('special')"
|
||||
/>
|
||||
<!-- hard-coded the special characters string because `$` indicates an i18n interpolation,
|
||||
and is handled inconsistently across browsers. Angular template syntax is used to
|
||||
ensure special characters are entity-encoded.
|
||||
-->
|
||||
<bit-label>{{ "!@#$%^&*" }}</bit-label>
|
||||
and is handled inconsistently across browsers. Angular template syntax is used to
|
||||
ensure special characters are entity-encoded.
|
||||
-->
|
||||
<bit-label>
|
||||
<span aria-hidden="true">{{ "!@#$%^&*" }}</span>
|
||||
<span class="tw-sr-only">
|
||||
{{ "specialCharactersDescription" | i18n }}
|
||||
</span>
|
||||
</bit-label>
|
||||
</bit-form-control>
|
||||
</div>
|
||||
<div class="tw-flex">
|
||||
@@ -97,7 +100,9 @@
|
||||
/>
|
||||
<bit-label>{{ "avoidAmbiguous" | i18n }}</bit-label>
|
||||
</bit-form-control>
|
||||
<p *ngIf="policyInEffect" bitTypography="helper">{{ "generatorPolicyInEffect" | i18n }}</p>
|
||||
@if (policyInEffect) {
|
||||
<p bitTypography="helper">{{ "generatorPolicyInEffect" | i18n }}</p>
|
||||
}
|
||||
</bit-card>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { coerceBooleanProperty } from "@angular/cdk/coercion";
|
||||
import { AsyncPipe } from "@angular/common";
|
||||
import {
|
||||
OnInit,
|
||||
Input,
|
||||
@@ -9,16 +10,27 @@ import {
|
||||
SimpleChanges,
|
||||
OnChanges,
|
||||
} from "@angular/core";
|
||||
import { FormBuilder } from "@angular/forms";
|
||||
import { FormBuilder, ReactiveFormsModule } from "@angular/forms";
|
||||
import { takeUntil, Subject, map, filter, tap, skip, ReplaySubject, withLatestFrom } from "rxjs";
|
||||
|
||||
import { JslibModule } from "@bitwarden/angular/jslib.module";
|
||||
import { Account } from "@bitwarden/common/auth/abstractions/account.service";
|
||||
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
||||
import {
|
||||
SectionComponent,
|
||||
SectionHeaderComponent,
|
||||
BaseCardDirective,
|
||||
CardComponent,
|
||||
FormFieldModule,
|
||||
TypographyModule,
|
||||
CheckboxModule,
|
||||
} from "@bitwarden/components";
|
||||
import {
|
||||
CredentialGeneratorService,
|
||||
PasswordGenerationOptions,
|
||||
BuiltIn,
|
||||
} from "@bitwarden/generator-core";
|
||||
import { I18nPipe } from "@bitwarden/ui-common";
|
||||
|
||||
import { hasRangeOfValues } from "./util";
|
||||
|
||||
@@ -39,7 +51,19 @@ const Controls = Object.freeze({
|
||||
@Component({
|
||||
selector: "tools-password-settings",
|
||||
templateUrl: "password-settings.component.html",
|
||||
standalone: false,
|
||||
imports: [
|
||||
SectionComponent,
|
||||
SectionHeaderComponent,
|
||||
TypographyModule,
|
||||
ReactiveFormsModule,
|
||||
BaseCardDirective,
|
||||
CardComponent,
|
||||
FormFieldModule,
|
||||
CheckboxModule,
|
||||
AsyncPipe,
|
||||
JslibModule,
|
||||
I18nPipe,
|
||||
],
|
||||
})
|
||||
export class PasswordSettingsComponent implements OnInit, OnChanges, OnDestroy {
|
||||
/** Instantiates the component
|
||||
|
||||
@@ -8,15 +8,18 @@ import {
|
||||
Output,
|
||||
SimpleChanges,
|
||||
} from "@angular/core";
|
||||
import { FormBuilder } from "@angular/forms";
|
||||
import { FormBuilder, ReactiveFormsModule } from "@angular/forms";
|
||||
import { map, ReplaySubject, skip, Subject, takeUntil, withLatestFrom } from "rxjs";
|
||||
|
||||
import { JslibModule } from "@bitwarden/angular/jslib.module";
|
||||
import { Account } from "@bitwarden/common/auth/abstractions/account.service";
|
||||
import { FormFieldModule } from "@bitwarden/components";
|
||||
import {
|
||||
CredentialGeneratorService,
|
||||
BuiltIn,
|
||||
SubaddressGenerationOptions,
|
||||
} from "@bitwarden/generator-core";
|
||||
import { I18nPipe } from "@bitwarden/ui-common";
|
||||
|
||||
/** Options group for plus-addressed emails */
|
||||
// FIXME(https://bitwarden.atlassian.net/browse/CL-764): Migrate to OnPush
|
||||
@@ -24,7 +27,7 @@ import {
|
||||
@Component({
|
||||
selector: "tools-subaddress-settings",
|
||||
templateUrl: "subaddress-settings.component.html",
|
||||
standalone: false,
|
||||
imports: [ReactiveFormsModule, FormFieldModule, JslibModule, I18nPipe],
|
||||
})
|
||||
export class SubaddressSettingsComponent implements OnInit, OnChanges, OnDestroy {
|
||||
/** Instantiates the component
|
||||
|
||||
@@ -42,42 +42,41 @@
|
||||
data-testid="username-type"
|
||||
>
|
||||
</bit-select>
|
||||
<bit-hint *ngIf="!!(credentialTypeHint$ | async)">{{
|
||||
credentialTypeHint$ | async
|
||||
}}</bit-hint>
|
||||
@if (credentialTypeHint$ | async) {
|
||||
<bit-hint>{{ credentialTypeHint$ | async }}</bit-hint>
|
||||
}
|
||||
</bit-form-field>
|
||||
</form>
|
||||
<form *ngIf="showForwarder$ | async" [formGroup]="forwarder" class="tw-container">
|
||||
<bit-form-field>
|
||||
<bit-label>{{ "service" | i18n }}</bit-label>
|
||||
<bit-select
|
||||
[items]="forwarderOptions$ | async"
|
||||
formControlName="nav"
|
||||
data-testid="email-forwarding-service"
|
||||
>
|
||||
</bit-select>
|
||||
</bit-form-field>
|
||||
</form>
|
||||
<tools-catchall-settings
|
||||
*ngIf="(showAlgorithm$ | async)?.id === Algorithm.catchall"
|
||||
[account]="account$ | async"
|
||||
(onUpdated)="generate('catchall settings')"
|
||||
/>
|
||||
<tools-forwarder-settings
|
||||
*ngIf="!!(forwarderId$ | async)"
|
||||
[forwarder]="forwarderId$ | async"
|
||||
[account]="account$ | async"
|
||||
/>
|
||||
<tools-subaddress-settings
|
||||
*ngIf="(showAlgorithm$ | async)?.id === Algorithm.plusAddress"
|
||||
[account]="account$ | async"
|
||||
(onUpdated)="generate('subaddress settings')"
|
||||
/>
|
||||
<tools-username-settings
|
||||
*ngIf="(showAlgorithm$ | async)?.id === Algorithm.username"
|
||||
[account]="account$ | async"
|
||||
(onUpdated)="generate('username settings')"
|
||||
/>
|
||||
@if (showForwarder$ | async) {
|
||||
<form [formGroup]="forwarder" class="tw-container">
|
||||
<bit-form-field>
|
||||
<bit-label>{{ "service" | i18n }}</bit-label>
|
||||
<bit-select
|
||||
[items]="forwarderOptions$ | async"
|
||||
formControlName="nav"
|
||||
data-testid="email-forwarding-service"
|
||||
>
|
||||
</bit-select>
|
||||
</bit-form-field>
|
||||
</form>
|
||||
}
|
||||
@let showAlgorithm = showAlgorithm$ | async;
|
||||
@let account = account$ | async;
|
||||
@if (showAlgorithm?.id === Algorithm.catchall) {
|
||||
<tools-catchall-settings [account]="account" (onUpdated)="generate('catchall settings')" />
|
||||
}
|
||||
@if (forwarderId$ | async; as forwarderId) {
|
||||
<tools-forwarder-settings [forwarder]="forwarderId" [account]="account" />
|
||||
}
|
||||
@if (showAlgorithm?.id === Algorithm.plusAddress) {
|
||||
<tools-subaddress-settings
|
||||
[account]="account"
|
||||
(onUpdated)="generate('subaddress settings')"
|
||||
/>
|
||||
}
|
||||
@if (showAlgorithm?.id === Algorithm.username) {
|
||||
<tools-username-settings [account]="account" (onUpdated)="generate('username settings')" />
|
||||
}
|
||||
</bit-card>
|
||||
</div>
|
||||
</bit-section>
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { LiveAnnouncer } from "@angular/cdk/a11y";
|
||||
import { coerceBooleanProperty } from "@angular/cdk/coercion";
|
||||
import { NgClass, AsyncPipe } from "@angular/common";
|
||||
import {
|
||||
Component,
|
||||
EventEmitter,
|
||||
@@ -11,7 +12,7 @@ import {
|
||||
Output,
|
||||
SimpleChanges,
|
||||
} from "@angular/core";
|
||||
import { FormBuilder } from "@angular/forms";
|
||||
import { FormBuilder, ReactiveFormsModule } from "@angular/forms";
|
||||
import {
|
||||
BehaviorSubject,
|
||||
catchError,
|
||||
@@ -28,6 +29,7 @@ import {
|
||||
withLatestFrom,
|
||||
} from "rxjs";
|
||||
|
||||
import { JslibModule } from "@bitwarden/angular/jslib.module";
|
||||
import { Account, AccountService } from "@bitwarden/common/auth/abstractions/account.service";
|
||||
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
||||
import { LogService } from "@bitwarden/common/platform/abstractions/log.service";
|
||||
@@ -38,7 +40,22 @@ import {
|
||||
ifEnabledSemanticLoggerProvider,
|
||||
} from "@bitwarden/common/tools/log";
|
||||
import { UserId } from "@bitwarden/common/types/guid";
|
||||
import { ToastService, Option } from "@bitwarden/components";
|
||||
import {
|
||||
ToastService,
|
||||
Option,
|
||||
AriaDisableDirective,
|
||||
BaseCardDirective,
|
||||
CardComponent,
|
||||
ColorPasswordComponent,
|
||||
CopyClickDirective,
|
||||
BitIconButtonComponent,
|
||||
TooltipDirective,
|
||||
SectionComponent,
|
||||
SectionHeaderComponent,
|
||||
SelectComponent,
|
||||
TypographyModule,
|
||||
FormFieldModule,
|
||||
} from "@bitwarden/components";
|
||||
import {
|
||||
AlgorithmInfo,
|
||||
CredentialGeneratorService,
|
||||
@@ -55,7 +72,12 @@ import {
|
||||
Algorithm,
|
||||
} from "@bitwarden/generator-core";
|
||||
import { GeneratorHistoryService } from "@bitwarden/generator-history";
|
||||
import { I18nPipe } from "@bitwarden/ui-common";
|
||||
|
||||
import { CatchallSettingsComponent } from "./catchall-settings.component";
|
||||
import { ForwarderSettingsComponent } from "./forwarder-settings.component";
|
||||
import { SubaddressSettingsComponent } from "./subaddress-settings.component";
|
||||
import { UsernameSettingsComponent } from "./username-settings.component";
|
||||
import { toAlgorithmInfo, translate } from "./util";
|
||||
|
||||
// constants used to identify navigation selections that are not
|
||||
@@ -69,7 +91,29 @@ const NONE_SELECTED = "none";
|
||||
@Component({
|
||||
selector: "tools-username-generator",
|
||||
templateUrl: "username-generator.component.html",
|
||||
standalone: false,
|
||||
imports: [
|
||||
BaseCardDirective,
|
||||
CardComponent,
|
||||
ColorPasswordComponent,
|
||||
AriaDisableDirective,
|
||||
TooltipDirective,
|
||||
BitIconButtonComponent,
|
||||
CopyClickDirective,
|
||||
SectionComponent,
|
||||
SectionHeaderComponent,
|
||||
TypographyModule,
|
||||
NgClass,
|
||||
ReactiveFormsModule,
|
||||
SelectComponent,
|
||||
FormFieldModule,
|
||||
CatchallSettingsComponent,
|
||||
ForwarderSettingsComponent,
|
||||
SubaddressSettingsComponent,
|
||||
UsernameSettingsComponent,
|
||||
AsyncPipe,
|
||||
JslibModule,
|
||||
I18nPipe,
|
||||
],
|
||||
})
|
||||
export class UsernameGeneratorComponent implements OnInit, OnChanges, OnDestroy {
|
||||
/** Instantiates the username generator
|
||||
|
||||
@@ -8,15 +8,18 @@ import {
|
||||
Output,
|
||||
SimpleChanges,
|
||||
} from "@angular/core";
|
||||
import { FormBuilder } from "@angular/forms";
|
||||
import { FormBuilder, ReactiveFormsModule } from "@angular/forms";
|
||||
import { map, ReplaySubject, skip, Subject, takeUntil, withLatestFrom } from "rxjs";
|
||||
|
||||
import { JslibModule } from "@bitwarden/angular/jslib.module";
|
||||
import { Account } from "@bitwarden/common/auth/abstractions/account.service";
|
||||
import { FormFieldModule, CheckboxModule } from "@bitwarden/components";
|
||||
import {
|
||||
CredentialGeneratorService,
|
||||
EffUsernameGenerationOptions,
|
||||
BuiltIn,
|
||||
} from "@bitwarden/generator-core";
|
||||
import { I18nPipe } from "@bitwarden/ui-common";
|
||||
|
||||
/** Options group for usernames */
|
||||
// FIXME(https://bitwarden.atlassian.net/browse/CL-764): Migrate to OnPush
|
||||
@@ -24,7 +27,7 @@ import {
|
||||
@Component({
|
||||
selector: "tools-username-settings",
|
||||
templateUrl: "username-settings.component.html",
|
||||
standalone: false,
|
||||
imports: [ReactiveFormsModule, FormFieldModule, CheckboxModule, JslibModule, I18nPipe],
|
||||
})
|
||||
export class UsernameSettingsComponent implements OnInit, OnChanges, OnDestroy {
|
||||
/** Instantiates the component
|
||||
|
||||
@@ -7,8 +7,7 @@ import { ForwarderContext } from "../forwarder-context";
|
||||
export class CreateForwardingAddressRpc<
|
||||
Settings extends ApiSettings,
|
||||
Req extends IntegrationRequest = IntegrationRequest,
|
||||
> implements JsonRpc<Req, string>
|
||||
{
|
||||
> implements JsonRpc<Req, string> {
|
||||
constructor(
|
||||
readonly requestor: ForwarderConfiguration<Settings>,
|
||||
readonly context: ForwarderContext<Settings>,
|
||||
|
||||
@@ -9,8 +9,7 @@ import { ForwarderContext } from "../forwarder-context";
|
||||
export class GetAccountIdRpc<
|
||||
Settings extends ApiSettings,
|
||||
Req extends IntegrationRequest = IntegrationRequest,
|
||||
> implements JsonRpc<Req, string>
|
||||
{
|
||||
> implements JsonRpc<Req, string> {
|
||||
constructor(
|
||||
readonly requestor: ForwarderConfiguration<Settings>,
|
||||
readonly context: ForwarderContext<Settings>,
|
||||
|
||||
@@ -24,6 +24,7 @@ describe("availableAlgorithms_vNextPolicy", () => {
|
||||
overridePasswordType: override,
|
||||
},
|
||||
enabled: true,
|
||||
revisionDate: new Date().toISOString(),
|
||||
});
|
||||
|
||||
const result = availableAlgorithms([policy]);
|
||||
@@ -44,6 +45,7 @@ describe("availableAlgorithms_vNextPolicy", () => {
|
||||
overridePasswordType: override,
|
||||
},
|
||||
enabled: true,
|
||||
revisionDate: new Date().toISOString(),
|
||||
});
|
||||
|
||||
const result = availableAlgorithms([policy, policy]);
|
||||
@@ -64,6 +66,7 @@ describe("availableAlgorithms_vNextPolicy", () => {
|
||||
overridePasswordType: "password",
|
||||
},
|
||||
enabled: true,
|
||||
revisionDate: new Date().toISOString(),
|
||||
});
|
||||
const passphrase = new Policy({
|
||||
id: "" as PolicyId,
|
||||
@@ -73,6 +76,7 @@ describe("availableAlgorithms_vNextPolicy", () => {
|
||||
overridePasswordType: "passphrase",
|
||||
},
|
||||
enabled: true,
|
||||
revisionDate: new Date().toISOString(),
|
||||
});
|
||||
|
||||
const result = availableAlgorithms([password, passphrase]);
|
||||
@@ -93,6 +97,7 @@ describe("availableAlgorithms_vNextPolicy", () => {
|
||||
some: "policy",
|
||||
},
|
||||
enabled: true,
|
||||
revisionDate: new Date().toISOString(),
|
||||
});
|
||||
|
||||
const result = availableAlgorithms([policy]);
|
||||
@@ -111,6 +116,7 @@ describe("availableAlgorithms_vNextPolicy", () => {
|
||||
some: "policy",
|
||||
},
|
||||
enabled: false,
|
||||
revisionDate: new Date().toISOString(),
|
||||
});
|
||||
|
||||
const result = availableAlgorithms([policy]);
|
||||
@@ -129,6 +135,7 @@ describe("availableAlgorithms_vNextPolicy", () => {
|
||||
some: "policy",
|
||||
},
|
||||
enabled: true,
|
||||
revisionDate: new Date().toISOString(),
|
||||
});
|
||||
|
||||
const result = availableAlgorithms([policy]);
|
||||
|
||||
@@ -2,9 +2,10 @@ import { PolicyEvaluator } from "../abstractions";
|
||||
import { NoPolicy } from "../types";
|
||||
|
||||
/** A policy evaluator that does not apply any policy */
|
||||
export class DefaultPolicyEvaluator<PolicyTarget>
|
||||
implements PolicyEvaluator<NoPolicy, PolicyTarget>
|
||||
{
|
||||
export class DefaultPolicyEvaluator<PolicyTarget> implements PolicyEvaluator<
|
||||
NoPolicy,
|
||||
PolicyTarget
|
||||
> {
|
||||
/** {@link PolicyEvaluator.policy} */
|
||||
get policy() {
|
||||
return {};
|
||||
|
||||
@@ -13,9 +13,7 @@ import { atLeast, atLeastSum, maybe, readonlyTrueWhen, AtLeastOne, Zero } from "
|
||||
import { PasswordPolicyConstraints } from "./password-policy-constraints";
|
||||
|
||||
/** Creates state constraints by blending policy and password settings. */
|
||||
export class DynamicPasswordPolicyConstraints
|
||||
implements DynamicStateConstraints<PasswordGeneratorSettings>
|
||||
{
|
||||
export class DynamicPasswordPolicyConstraints implements DynamicStateConstraints<PasswordGeneratorSettings> {
|
||||
/** Instantiates the object.
|
||||
* @param policy the password policy to enforce. This cannot be
|
||||
* `null` or `undefined`.
|
||||
|
||||
@@ -17,6 +17,7 @@ function createPolicy(
|
||||
data,
|
||||
enabled,
|
||||
type,
|
||||
revisionDate: new Date().toISOString(),
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -17,6 +17,7 @@ function createPolicy(
|
||||
data,
|
||||
enabled,
|
||||
type,
|
||||
revisionDate: new Date().toISOString(),
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -25,7 +25,11 @@ import { deepFreeze } from "@bitwarden/common/tools/util";
|
||||
import { UserId } from "@bitwarden/common/types/guid";
|
||||
import { BitwardenClient } from "@bitwarden/sdk-internal";
|
||||
|
||||
import { FakeAccountService, FakeStateProvider } from "../../../../../common/spec";
|
||||
import {
|
||||
FakeAccountService,
|
||||
FakeStateProvider,
|
||||
mockAccountInfoWith,
|
||||
} from "../../../../../common/spec";
|
||||
import { Algorithm, AlgorithmsByType, CredentialAlgorithm, Type, Types } from "../metadata";
|
||||
import catchall from "../metadata/email/catchall";
|
||||
import plusAddress from "../metadata/email/plus-address";
|
||||
@@ -40,9 +44,10 @@ import { GeneratorMetadataProvider } from "./generator-metadata-provider";
|
||||
const SomeUser = "some user" as UserId;
|
||||
const SomeAccount = {
|
||||
id: SomeUser,
|
||||
email: "someone@example.com",
|
||||
emailVerified: true,
|
||||
name: "Someone",
|
||||
...mockAccountInfoWith({
|
||||
email: "someone@example.com",
|
||||
name: "Someone",
|
||||
}),
|
||||
};
|
||||
const SomeAccount$ = new BehaviorSubject<Account>(SomeAccount);
|
||||
|
||||
|
||||
@@ -15,7 +15,12 @@ import { UserStateSubjectDependencyProvider } from "@bitwarden/common/tools/stat
|
||||
import { StateConstraints } from "@bitwarden/common/tools/types";
|
||||
import { OrganizationId, PolicyId, UserId } from "@bitwarden/common/types/guid";
|
||||
|
||||
import { FakeStateProvider, FakeAccountService, awaitAsync } from "../../../../../common/spec";
|
||||
import {
|
||||
FakeStateProvider,
|
||||
FakeAccountService,
|
||||
awaitAsync,
|
||||
mockAccountInfoWith,
|
||||
} from "../../../../../common/spec";
|
||||
import { CoreProfileMetadata, ProfileContext } from "../metadata/profile-metadata";
|
||||
import { GeneratorConstraints } from "../types";
|
||||
|
||||
@@ -31,21 +36,25 @@ const UnverifiedEmailUser = "UnverifiedEmailUser" as UserId;
|
||||
const accounts: Record<UserId, Account> = {
|
||||
[SomeUser]: {
|
||||
id: SomeUser,
|
||||
name: "some user",
|
||||
email: "some.user@example.com",
|
||||
emailVerified: true,
|
||||
...mockAccountInfoWith({
|
||||
name: "some user",
|
||||
email: "some.user@example.com",
|
||||
}),
|
||||
},
|
||||
[AnotherUser]: {
|
||||
id: AnotherUser,
|
||||
name: "some other user",
|
||||
email: "some.other.user@example.com",
|
||||
emailVerified: true,
|
||||
...mockAccountInfoWith({
|
||||
name: "some other user",
|
||||
email: "some.other.user@example.com",
|
||||
}),
|
||||
},
|
||||
[UnverifiedEmailUser]: {
|
||||
id: UnverifiedEmailUser,
|
||||
name: "a user with an unverfied email",
|
||||
email: "unverified@example.com",
|
||||
emailVerified: false,
|
||||
...mockAccountInfoWith({
|
||||
name: "a user with an unverfied email",
|
||||
email: "unverified@example.com",
|
||||
emailVerified: false,
|
||||
}),
|
||||
},
|
||||
};
|
||||
const accountService = new FakeAccountService(accounts);
|
||||
@@ -57,6 +66,7 @@ const somePolicy = new Policy({
|
||||
id: "" as PolicyId,
|
||||
organizationId: "" as OrganizationId,
|
||||
enabled: true,
|
||||
revisionDate: new Date().toISOString(),
|
||||
});
|
||||
|
||||
const stateProvider = new FakeStateProvider(accountService);
|
||||
|
||||
@@ -8,7 +8,7 @@ import { Vendor } from "@bitwarden/common/tools/extension/vendor/data";
|
||||
import { SemanticLogger, ifEnabledSemanticLoggerProvider } from "@bitwarden/common/tools/log";
|
||||
import { UserId } from "@bitwarden/common/types/guid";
|
||||
|
||||
import { awaitAsync } from "../../../../../common/spec";
|
||||
import { awaitAsync, mockAccountInfoWith } from "../../../../../common/spec";
|
||||
import {
|
||||
Algorithm,
|
||||
CredentialAlgorithm,
|
||||
@@ -56,9 +56,10 @@ describe("DefaultCredentialGeneratorService", () => {
|
||||
// Use a hard-coded value for mockAccount
|
||||
account = {
|
||||
id: "test-account-id" as UserId,
|
||||
emailVerified: true,
|
||||
email: "test@example.com",
|
||||
name: "Test User",
|
||||
...mockAccountInfoWith({
|
||||
email: "test@example.com",
|
||||
name: "Test User",
|
||||
}),
|
||||
};
|
||||
|
||||
system = {
|
||||
|
||||
@@ -13,9 +13,10 @@ import { observe$PerUserId, sharedStateByUserId } from "../util";
|
||||
import { CATCHALL_SETTINGS } from "./storage";
|
||||
|
||||
/** Strategy for creating usernames using a catchall email address */
|
||||
export class CatchallGeneratorStrategy
|
||||
implements GeneratorStrategy<CatchallGenerationOptions, NoPolicy>
|
||||
{
|
||||
export class CatchallGeneratorStrategy implements GeneratorStrategy<
|
||||
CatchallGenerationOptions,
|
||||
NoPolicy
|
||||
> {
|
||||
/** Instantiates the generation strategy
|
||||
* @param usernameService generates a catchall address for a domain
|
||||
*/
|
||||
|
||||
@@ -16,9 +16,10 @@ const UsernameDigits = Object.freeze({
|
||||
});
|
||||
|
||||
/** Strategy for creating usernames from the EFF wordlist */
|
||||
export class EffUsernameGeneratorStrategy
|
||||
implements GeneratorStrategy<EffUsernameGenerationOptions, NoPolicy>
|
||||
{
|
||||
export class EffUsernameGeneratorStrategy implements GeneratorStrategy<
|
||||
EffUsernameGenerationOptions,
|
||||
NoPolicy
|
||||
> {
|
||||
/** Instantiates the generation strategy
|
||||
* @param usernameService generates a username from EFF word list
|
||||
*/
|
||||
|
||||
@@ -10,8 +10,7 @@ import { Classifier } from "@bitwarden/common/tools/state/classifier";
|
||||
export class OptionsClassifier<
|
||||
Settings,
|
||||
Options extends IntegrationRequest & Settings = IntegrationRequest & Settings,
|
||||
> implements Classifier<Options, Record<string, never>, Settings>
|
||||
{
|
||||
> implements Classifier<Options, Record<string, never>, Settings> {
|
||||
/** Partitions `secret` into its disclosed properties and secret properties.
|
||||
* @param value The object to partition
|
||||
* @returns an object that classifies secrets.
|
||||
|
||||
@@ -14,9 +14,10 @@ import { observe$PerUserId, optionsToEffWordListRequest, sharedStateByUserId } f
|
||||
import { PASSPHRASE_SETTINGS } from "./storage";
|
||||
|
||||
/** Generates passphrases composed of random words */
|
||||
export class PassphraseGeneratorStrategy
|
||||
implements GeneratorStrategy<PassphraseGenerationOptions, PassphraseGeneratorPolicy>
|
||||
{
|
||||
export class PassphraseGeneratorStrategy implements GeneratorStrategy<
|
||||
PassphraseGenerationOptions,
|
||||
PassphraseGeneratorPolicy
|
||||
> {
|
||||
/** instantiates the password generator strategy.
|
||||
* @param legacy generates the passphrase
|
||||
* @param stateProvider provides durable state
|
||||
|
||||
@@ -12,9 +12,10 @@ import { observe$PerUserId, optionsToRandomAsciiRequest, sharedStateByUserId } f
|
||||
import { PASSWORD_SETTINGS } from "./storage";
|
||||
|
||||
/** Generates passwords composed of random characters */
|
||||
export class PasswordGeneratorStrategy
|
||||
implements GeneratorStrategy<PasswordGenerationOptions, PasswordGeneratorPolicy>
|
||||
{
|
||||
export class PasswordGeneratorStrategy implements GeneratorStrategy<
|
||||
PasswordGenerationOptions,
|
||||
PasswordGeneratorPolicy
|
||||
> {
|
||||
/** instantiates the password generator strategy.
|
||||
* @param legacy generates the password
|
||||
*/
|
||||
|
||||
@@ -17,9 +17,10 @@ import { SUBADDRESS_SETTINGS } from "./storage";
|
||||
* For example, if the email address is `jd+xyz@domain.io`,
|
||||
* the subaddress is `xyz`.
|
||||
*/
|
||||
export class SubaddressGeneratorStrategy
|
||||
implements GeneratorStrategy<SubaddressGenerationOptions, NoPolicy>
|
||||
{
|
||||
export class SubaddressGeneratorStrategy implements GeneratorStrategy<
|
||||
SubaddressGenerationOptions,
|
||||
NoPolicy
|
||||
> {
|
||||
/** Instantiates the generation strategy
|
||||
* @param usernameService generates an email subaddress from an email address
|
||||
*/
|
||||
|
||||
@@ -70,6 +70,7 @@ describe("DefaultGeneratorNavigationService", () => {
|
||||
enabled: true,
|
||||
type: PolicyType.PasswordGenerator,
|
||||
data: { overridePasswordType: "password" },
|
||||
revisionDate: new Date().toISOString(),
|
||||
}),
|
||||
]);
|
||||
},
|
||||
|
||||
@@ -8,9 +8,10 @@ import { GeneratorNavigationPolicy } from "./generator-navigation-policy";
|
||||
|
||||
/** Enforces policy for generator navigation options.
|
||||
*/
|
||||
export class GeneratorNavigationEvaluator
|
||||
implements PolicyEvaluator<GeneratorNavigationPolicy, GeneratorNavigation>
|
||||
{
|
||||
export class GeneratorNavigationEvaluator implements PolicyEvaluator<
|
||||
GeneratorNavigationPolicy,
|
||||
GeneratorNavigation
|
||||
> {
|
||||
/** Instantiates the evaluator.
|
||||
* @param policy The policy applied by the evaluator. When this conflicts with
|
||||
* the defaults, the policy takes precedence.
|
||||
|
||||
@@ -17,6 +17,7 @@ function createPolicy(
|
||||
data,
|
||||
enabled,
|
||||
type,
|
||||
revisionDate: new Date().toISOString(),
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user