mirror of
https://github.com/bitwarden/browser.git
synced 2024-10-22 07:50:04 +02:00
finish forwarder drilldown
This commit is contained in:
parent
c48ddd8ecd
commit
32aa0429bb
@ -3,7 +3,7 @@
|
|||||||
fullWidth
|
fullWidth
|
||||||
class="tw-mb-4"
|
class="tw-mb-4"
|
||||||
[selected]="(root$ | async).nav"
|
[selected]="(root$ | async).nav"
|
||||||
(selectedChange)="onRootChanged($event)"
|
(selectedChange)="onRootChanged({ nav: $event })"
|
||||||
attr.aria-label="{{ 'type' | i18n }}"
|
attr.aria-label="{{ 'type' | i18n }}"
|
||||||
>
|
>
|
||||||
<bit-toggle *ngFor="let option of rootOptions$ | async" [value]="option.value">
|
<bit-toggle *ngFor="let option of rootOptions$ | async" [value]="option.value">
|
||||||
@ -57,6 +57,12 @@
|
|||||||
}}</bit-hint>
|
}}</bit-hint>
|
||||||
</bit-form-field>
|
</bit-form-field>
|
||||||
</form>
|
</form>
|
||||||
|
<form class="box" [formGroup]="forwarder" class="tw-container">
|
||||||
|
<bit-form-field>
|
||||||
|
<bit-label>{{ "forwarder" | i18n }}</bit-label>
|
||||||
|
<bit-select [items]="forwarderOptions$ | async" formControlName="forwarder"> </bit-select>
|
||||||
|
</bit-form-field>
|
||||||
|
</form>
|
||||||
<tools-catchall-settings
|
<tools-catchall-settings
|
||||||
*ngIf="(algorithm$ | async)?.id === 'catchall'"
|
*ngIf="(algorithm$ | async)?.id === 'catchall'"
|
||||||
[userId]="userId$ | async"
|
[userId]="userId$ | async"
|
||||||
|
@ -23,6 +23,8 @@ import {
|
|||||||
CredentialAlgorithm,
|
CredentialAlgorithm,
|
||||||
CredentialCategory,
|
CredentialCategory,
|
||||||
CredentialGeneratorService,
|
CredentialGeneratorService,
|
||||||
|
EmailAlgorithm,
|
||||||
|
ForwarderIntegration,
|
||||||
GeneratedCredential,
|
GeneratedCredential,
|
||||||
Generators,
|
Generators,
|
||||||
getForwarderConfiguration,
|
getForwarderConfiguration,
|
||||||
@ -32,6 +34,7 @@ import {
|
|||||||
isUsernameAlgorithm,
|
isUsernameAlgorithm,
|
||||||
PasswordAlgorithm,
|
PasswordAlgorithm,
|
||||||
toCredentialGeneratorConfiguration,
|
toCredentialGeneratorConfiguration,
|
||||||
|
UsernameAlgorithm,
|
||||||
} from "@bitwarden/generator-core";
|
} from "@bitwarden/generator-core";
|
||||||
|
|
||||||
/** root category that drills into username and email categories */
|
/** root category that drills into username and email categories */
|
||||||
@ -39,6 +42,12 @@ const IDENTIFIER = "identifier";
|
|||||||
/** options available for the top-level navigation */
|
/** options available for the top-level navigation */
|
||||||
type RootNavValue = PasswordAlgorithm | typeof IDENTIFIER;
|
type RootNavValue = PasswordAlgorithm | typeof IDENTIFIER;
|
||||||
|
|
||||||
|
const FORWARDER = "forwarder";
|
||||||
|
type UsernameNavValue = UsernameAlgorithm | EmailAlgorithm | typeof FORWARDER;
|
||||||
|
|
||||||
|
const NONE_SELECTED = "none";
|
||||||
|
type ForwarderNavValue = ForwarderIntegration | typeof NONE_SELECTED;
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: "tools-credential-generator",
|
selector: "tools-credential-generator",
|
||||||
templateUrl: "credential-generator.component.html",
|
templateUrl: "credential-generator.component.html",
|
||||||
@ -66,17 +75,21 @@ export class CredentialGeneratorComponent implements OnInit, OnDestroy {
|
|||||||
nav: null,
|
nav: null,
|
||||||
});
|
});
|
||||||
|
|
||||||
protected onRootChanged(nav: RootNavValue) {
|
protected onRootChanged(value: { nav: RootNavValue }) {
|
||||||
// prevent subscription cycle
|
// prevent subscription cycle
|
||||||
if (this.root$.value.nav !== nav) {
|
if (this.root$.value.nav !== value.nav) {
|
||||||
this.zone.run(() => {
|
this.zone.run(() => {
|
||||||
this.root$.next({ nav });
|
this.root$.next(value);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected username = this.formBuilder.group({
|
protected username = this.formBuilder.group({
|
||||||
nav: [null as CredentialAlgorithm],
|
nav: [null as UsernameNavValue],
|
||||||
|
});
|
||||||
|
|
||||||
|
protected forwarder = this.formBuilder.group({
|
||||||
|
nav: [null as ForwarderNavValue],
|
||||||
});
|
});
|
||||||
|
|
||||||
async ngOnInit() {
|
async ngOnInit() {
|
||||||
@ -95,10 +108,23 @@ export class CredentialGeneratorComponent implements OnInit, OnDestroy {
|
|||||||
this.generatorService
|
this.generatorService
|
||||||
.algorithms$(["email", "username"], { userId$: this.userId$ })
|
.algorithms$(["email", "username"], { userId$: this.userId$ })
|
||||||
.pipe(
|
.pipe(
|
||||||
map((algorithms) => this.toOptions(algorithms)),
|
map((algorithms) => {
|
||||||
|
const usernames = algorithms.filter((a) => !isForwarderIntegration(a.id));
|
||||||
|
const usernameOptions = this.toOptions(usernames) as Option<UsernameNavValue>[];
|
||||||
|
usernameOptions.push({ value: FORWARDER, label: this.i18nService.t("forwarder") });
|
||||||
|
|
||||||
|
const forwarders = algorithms.filter((a) => isForwarderIntegration(a.id));
|
||||||
|
const forwarderOptions = this.toOptions(forwarders) as Option<ForwarderNavValue>[];
|
||||||
|
forwarderOptions.unshift({ value: NONE_SELECTED, label: this.i18nService.t("select") });
|
||||||
|
|
||||||
|
return [usernameOptions, forwarderOptions] as const;
|
||||||
|
}),
|
||||||
takeUntil(this.destroyed),
|
takeUntil(this.destroyed),
|
||||||
)
|
)
|
||||||
.subscribe(this.usernameOptions$);
|
.subscribe(([usernames, forwarders]) => {
|
||||||
|
this.usernameOptions$.next(usernames);
|
||||||
|
this.forwarderOptions$.next(forwarders);
|
||||||
|
});
|
||||||
|
|
||||||
this.generatorService
|
this.generatorService
|
||||||
.algorithms$("password", { userId$: this.userId$ })
|
.algorithms$("password", { userId$: this.userId$ })
|
||||||
@ -166,11 +192,18 @@ export class CredentialGeneratorComponent implements OnInit, OnDestroy {
|
|||||||
return of(root as { nav: CredentialAlgorithm });
|
return of(root as { nav: CredentialAlgorithm });
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
switchMap((tier1) => {
|
switchMap((username) => {
|
||||||
if (tier1.nav === FORWARDER) {
|
if (username.nav === FORWARDER) {
|
||||||
return concat(of(this.forwarder.value), this.forwarder.valueChanges);
|
return concat(of(this.forwarder.value), this.forwarder.valueChanges);
|
||||||
} else {
|
} else {
|
||||||
return of(tier1 as { nav: CredentialAlgorithm });
|
return of(username as { nav: CredentialAlgorithm });
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
map((forwarder) => {
|
||||||
|
if (forwarder.nav === NONE_SELECTED) {
|
||||||
|
return { nav: null };
|
||||||
|
} else {
|
||||||
|
return forwarder as { nav: CredentialAlgorithm };
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
filter(({ nav }) => !!nav),
|
filter(({ nav }) => !!nav),
|
||||||
@ -201,16 +234,27 @@ export class CredentialGeneratorComponent implements OnInit, OnDestroy {
|
|||||||
// populate the form with the user's preferences to kick off interactivity
|
// populate the form with the user's preferences to kick off interactivity
|
||||||
preferences.pipe(takeUntil(this.destroyed)).subscribe(({ email, username, password }) => {
|
preferences.pipe(takeUntil(this.destroyed)).subscribe(({ email, username, password }) => {
|
||||||
// the last preference set by the user "wins"
|
// the last preference set by the user "wins"
|
||||||
const userNav = email.updated > username.updated ? email : username;
|
const forwarderPref = isForwarderIntegration(email.algorithm) ? email : null;
|
||||||
const rootNav: any = userNav.updated > password.updated ? IDENTIFIER : password.algorithm;
|
const usernamePref = email.updated > username.updated ? email : username;
|
||||||
const credentialType = rootNav === IDENTIFIER ? userNav.algorithm : password.algorithm;
|
const rootPref = username.updated > password.updated ? username : password;
|
||||||
|
|
||||||
|
// inject drilldown flags
|
||||||
|
const forwarderNav = !forwarderPref
|
||||||
|
? NONE_SELECTED
|
||||||
|
: (forwarderPref.algorithm as ForwarderIntegration);
|
||||||
|
const userNav = forwarderPref ? FORWARDER : (usernamePref.algorithm as UsernameAlgorithm);
|
||||||
|
const rootNav =
|
||||||
|
rootPref.algorithm == usernamePref.algorithm
|
||||||
|
? IDENTIFIER
|
||||||
|
: (rootPref.algorithm as PasswordAlgorithm);
|
||||||
|
|
||||||
// update navigation; break subscription loop
|
// update navigation; break subscription loop
|
||||||
this.onRootChanged(rootNav);
|
this.onRootChanged({ nav: rootNav });
|
||||||
this.username.setValue({ nav: userNav.algorithm }, { emitEvent: false });
|
this.username.setValue({ nav: userNav }, { emitEvent: false });
|
||||||
|
this.forwarder.setValue({ nav: forwarderNav }, { emitEvent: false });
|
||||||
|
|
||||||
// load algorithm metadata
|
// load algorithm metadata
|
||||||
const algorithm = this.generatorService.algorithm(credentialType);
|
const algorithm = this.generatorService.algorithm(rootPref.algorithm);
|
||||||
|
|
||||||
// update subjects within the angular zone so that the
|
// update subjects within the angular zone so that the
|
||||||
// template bindings refresh immediately
|
// template bindings refresh immediately
|
||||||
@ -261,12 +305,15 @@ export class CredentialGeneratorComponent implements OnInit, OnDestroy {
|
|||||||
throw new Error(`Invalid generator type: "${type}"`);
|
throw new Error(`Invalid generator type: "${type}"`);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Lists the credential types of the username algorithm box. */
|
|
||||||
protected usernameOptions$ = new BehaviorSubject<Option<CredentialAlgorithm>[]>([]);
|
|
||||||
|
|
||||||
/** Lists the top-level credential types supported by the component. */
|
/** Lists the top-level credential types supported by the component. */
|
||||||
protected rootOptions$ = new BehaviorSubject<Option<RootNavValue>[]>([]);
|
protected rootOptions$ = new BehaviorSubject<Option<RootNavValue>[]>([]);
|
||||||
|
|
||||||
|
/** Lists the credential types of the username algorithm box. */
|
||||||
|
protected usernameOptions$ = new BehaviorSubject<Option<UsernameNavValue>[]>([]);
|
||||||
|
|
||||||
|
/** Lists the credential types of the username algorithm box. */
|
||||||
|
protected forwarderOptions$ = new BehaviorSubject<Option<ForwarderNavValue>[]>([]);
|
||||||
|
|
||||||
/** tracks the currently selected credential type */
|
/** tracks the currently selected credential type */
|
||||||
protected algorithm$ = new ReplaySubject<AlgorithmInfo>(1);
|
protected algorithm$ = new ReplaySubject<AlgorithmInfo>(1);
|
||||||
|
|
||||||
|
@ -23,20 +23,19 @@
|
|||||||
</bit-section-header>
|
</bit-section-header>
|
||||||
<div class="tw-mb-4">
|
<div class="tw-mb-4">
|
||||||
<bit-card>
|
<bit-card>
|
||||||
<form class="box" [formGroup]="credential" class="tw-container">
|
<form class="box" [formGroup]="username" class="tw-container">
|
||||||
<bit-form-field>
|
<bit-form-field>
|
||||||
<bit-label>{{ "type" | i18n }}</bit-label>
|
<bit-label>{{ "type" | i18n }}</bit-label>
|
||||||
<bit-select [items]="typeOptions$ | async" formControlName="type"> </bit-select>
|
<bit-select [items]="typeOptions$ | async" formControlName="nav"> </bit-select>
|
||||||
<bit-hint *ngIf="!!(credentialTypeHint$ | async)">{{
|
<bit-hint *ngIf="!!(credentialTypeHint$ | async)">{{
|
||||||
credentialTypeHint$ | async
|
credentialTypeHint$ | async
|
||||||
}}</bit-hint>
|
}}</bit-hint>
|
||||||
</bit-form-field>
|
</bit-form-field>
|
||||||
|
</form>
|
||||||
|
<form class="box" [formGroup]="forwarder" class="tw-container">
|
||||||
<bit-form-field>
|
<bit-form-field>
|
||||||
<bit-label>{{ "forwarder" | i18n }}</bit-label>
|
<bit-label>{{ "forwarder" | i18n }}</bit-label>
|
||||||
<bit-select [items]="forwarderOptions$ | async" formControlName="forwarder"> </bit-select>
|
<bit-select [items]="forwarderOptions$ | async" formControlName="nav"> </bit-select>
|
||||||
<bit-hint *ngIf="!!(forwarderTypeHint$ | async)">{{
|
|
||||||
forwarderTypeHint$ | async
|
|
||||||
}}</bit-hint>
|
|
||||||
</bit-form-field>
|
</bit-form-field>
|
||||||
</form>
|
</form>
|
||||||
<tools-catchall-settings
|
<tools-catchall-settings
|
||||||
|
@ -2,9 +2,11 @@ import { Component, EventEmitter, Input, NgZone, OnDestroy, OnInit, Output } fro
|
|||||||
import { FormBuilder } from "@angular/forms";
|
import { FormBuilder } from "@angular/forms";
|
||||||
import {
|
import {
|
||||||
BehaviorSubject,
|
BehaviorSubject,
|
||||||
|
concat,
|
||||||
distinctUntilChanged,
|
distinctUntilChanged,
|
||||||
filter,
|
filter,
|
||||||
map,
|
map,
|
||||||
|
of,
|
||||||
ReplaySubject,
|
ReplaySubject,
|
||||||
Subject,
|
Subject,
|
||||||
switchMap,
|
switchMap,
|
||||||
@ -20,6 +22,8 @@ import {
|
|||||||
AlgorithmInfo,
|
AlgorithmInfo,
|
||||||
CredentialAlgorithm,
|
CredentialAlgorithm,
|
||||||
CredentialGeneratorService,
|
CredentialGeneratorService,
|
||||||
|
EmailAlgorithm,
|
||||||
|
ForwarderIntegration,
|
||||||
GeneratedCredential,
|
GeneratedCredential,
|
||||||
Generators,
|
Generators,
|
||||||
getForwarderConfiguration,
|
getForwarderConfiguration,
|
||||||
@ -27,8 +31,15 @@ import {
|
|||||||
isForwarderIntegration,
|
isForwarderIntegration,
|
||||||
isUsernameAlgorithm,
|
isUsernameAlgorithm,
|
||||||
toCredentialGeneratorConfiguration,
|
toCredentialGeneratorConfiguration,
|
||||||
|
UsernameAlgorithm,
|
||||||
} from "@bitwarden/generator-core";
|
} from "@bitwarden/generator-core";
|
||||||
|
|
||||||
|
const FORWARDER = "forwarder";
|
||||||
|
type UsernameNavValue = UsernameAlgorithm | EmailAlgorithm | typeof FORWARDER;
|
||||||
|
|
||||||
|
const NONE_SELECTED = "none";
|
||||||
|
type ForwarderNavValue = ForwarderIntegration | typeof NONE_SELECTED;
|
||||||
|
|
||||||
/** Component that generates usernames and emails */
|
/** Component that generates usernames and emails */
|
||||||
@Component({
|
@Component({
|
||||||
selector: "tools-username-generator",
|
selector: "tools-username-generator",
|
||||||
@ -61,8 +72,12 @@ export class UsernameGeneratorComponent implements OnInit, OnDestroy {
|
|||||||
readonly onGenerated = new EventEmitter<GeneratedCredential>();
|
readonly onGenerated = new EventEmitter<GeneratedCredential>();
|
||||||
|
|
||||||
/** Tracks the selected generation algorithm */
|
/** Tracks the selected generation algorithm */
|
||||||
protected credential = this.formBuilder.group({
|
protected username = this.formBuilder.group({
|
||||||
type: [null as CredentialAlgorithm],
|
nav: [null as UsernameNavValue],
|
||||||
|
});
|
||||||
|
|
||||||
|
protected forwarder = this.formBuilder.group({
|
||||||
|
nav: [null as ForwarderNavValue],
|
||||||
});
|
});
|
||||||
|
|
||||||
async ngOnInit() {
|
async ngOnInit() {
|
||||||
@ -81,18 +96,22 @@ export class UsernameGeneratorComponent implements OnInit, OnDestroy {
|
|||||||
this.generatorService
|
this.generatorService
|
||||||
.algorithms$(["email", "username"], { userId$: this.userId$ })
|
.algorithms$(["email", "username"], { userId$: this.userId$ })
|
||||||
.pipe(
|
.pipe(
|
||||||
map(
|
map((algorithms) => {
|
||||||
(algorithms) =>
|
const usernames = algorithms.filter((a) => !isForwarderIntegration(a.id));
|
||||||
[
|
const usernameOptions = this.toOptions(usernames) as Option<UsernameNavValue>[];
|
||||||
this.toOptions(algorithms.filter((a) => !isForwarderIntegration(a.id))),
|
usernameOptions.push({ value: FORWARDER, label: this.i18nService.t("forwarder") });
|
||||||
this.toOptions(algorithms.filter((a) => isForwarderIntegration(a.id))),
|
|
||||||
] as const,
|
const forwarders = algorithms.filter((a) => isForwarderIntegration(a.id));
|
||||||
),
|
const forwarderOptions = this.toOptions(forwarders) as Option<ForwarderNavValue>[];
|
||||||
|
forwarderOptions.unshift({ value: NONE_SELECTED, label: this.i18nService.t("select") });
|
||||||
|
|
||||||
|
return [usernameOptions, forwarderOptions] as const;
|
||||||
|
}),
|
||||||
takeUntil(this.destroyed),
|
takeUntil(this.destroyed),
|
||||||
)
|
)
|
||||||
.subscribe(([type, forwarder]) => {
|
.subscribe(([usernames, forwarders]) => {
|
||||||
this.typeOptions$.next(type);
|
this.typeOptions$.next(usernames);
|
||||||
this.forwarderOptions$.next(forwarder);
|
this.forwarderOptions$.next(forwarders);
|
||||||
});
|
});
|
||||||
|
|
||||||
this.algorithm$
|
this.algorithm$
|
||||||
@ -125,18 +144,32 @@ export class UsernameGeneratorComponent implements OnInit, OnDestroy {
|
|||||||
|
|
||||||
// assume the last-visible generator algorithm is the user's preferred one
|
// assume the last-visible generator algorithm is the user's preferred one
|
||||||
const preferences = await this.generatorService.preferences({ singleUserId$: this.userId$ });
|
const preferences = await this.generatorService.preferences({ singleUserId$: this.userId$ });
|
||||||
this.credential.valueChanges
|
this.username.valueChanges
|
||||||
.pipe(
|
.pipe(
|
||||||
filter(({ type }) => !!type),
|
switchMap((username) => {
|
||||||
|
if (username.nav === FORWARDER) {
|
||||||
|
return concat(of(this.forwarder.value), this.forwarder.valueChanges);
|
||||||
|
} else {
|
||||||
|
return of(username as { nav: CredentialAlgorithm });
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
map((forwarder) => {
|
||||||
|
if (forwarder.nav === NONE_SELECTED) {
|
||||||
|
return { nav: null };
|
||||||
|
} else {
|
||||||
|
return forwarder as { nav: CredentialAlgorithm };
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
filter(({ nav }) => !!nav),
|
||||||
withLatestFrom(preferences),
|
withLatestFrom(preferences),
|
||||||
takeUntil(this.destroyed),
|
takeUntil(this.destroyed),
|
||||||
)
|
)
|
||||||
.subscribe(([{ type }, preference]) => {
|
.subscribe(([{ nav: algorithm }, preference]) => {
|
||||||
if (isEmailAlgorithm(type)) {
|
if (isEmailAlgorithm(algorithm)) {
|
||||||
preference.email.algorithm = type;
|
preference.email.algorithm = algorithm;
|
||||||
preference.email.updated = new Date();
|
preference.email.updated = new Date();
|
||||||
} else if (isUsernameAlgorithm(type)) {
|
} else if (isUsernameAlgorithm(algorithm)) {
|
||||||
preference.username.algorithm = type;
|
preference.username.algorithm = algorithm;
|
||||||
preference.username.updated = new Date();
|
preference.username.updated = new Date();
|
||||||
} else {
|
} else {
|
||||||
return;
|
return;
|
||||||
@ -147,14 +180,23 @@ export class UsernameGeneratorComponent implements OnInit, OnDestroy {
|
|||||||
|
|
||||||
// populate the form with the user's preferences to kick off interactivity
|
// populate the form with the user's preferences to kick off interactivity
|
||||||
preferences.pipe(takeUntil(this.destroyed)).subscribe(({ email, username }) => {
|
preferences.pipe(takeUntil(this.destroyed)).subscribe(({ email, username }) => {
|
||||||
// this generator supports email & username; the last preference
|
// the last preference set by the user "wins"
|
||||||
// set by the user "wins"
|
const forwarderPref = isForwarderIntegration(email.algorithm) ? email : null;
|
||||||
const preference = email.updated > username.updated ? email.algorithm : username.algorithm;
|
const usernamePref = email.updated > username.updated ? email : username;
|
||||||
|
|
||||||
// break subscription loop
|
// inject drilldown flags
|
||||||
this.credential.setValue({ type: preference }, { emitEvent: false });
|
const forwarderNav = forwarderPref
|
||||||
|
? (forwarderPref.algorithm as ForwarderIntegration)
|
||||||
|
: NONE_SELECTED;
|
||||||
|
const userNav = forwarderPref ? FORWARDER : (usernamePref.algorithm as UsernameAlgorithm);
|
||||||
|
|
||||||
|
// update navigation; break subscription loop
|
||||||
|
this.username.setValue({ nav: userNav }, { emitEvent: false });
|
||||||
|
this.forwarder.setValue({ nav: forwarderNav }, { emitEvent: false });
|
||||||
|
|
||||||
|
// load selected algorithm metadata
|
||||||
|
const algorithm = this.generatorService.algorithm(usernamePref.algorithm);
|
||||||
|
|
||||||
const algorithm = this.generatorService.algorithm(preference);
|
|
||||||
// update subjects within the angular zone so that the
|
// update subjects within the angular zone so that the
|
||||||
// template bindings refresh immediately
|
// template bindings refresh immediately
|
||||||
this.zone.run(() => {
|
this.zone.run(() => {
|
||||||
@ -199,10 +241,10 @@ export class UsernameGeneratorComponent implements OnInit, OnDestroy {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** Lists the credential types supported by the component. */
|
/** Lists the credential types supported by the component. */
|
||||||
protected typeOptions$ = new BehaviorSubject<Option<CredentialAlgorithm>[]>([]);
|
protected typeOptions$ = new BehaviorSubject<Option<UsernameNavValue>[]>([]);
|
||||||
|
|
||||||
/** Lists the credential types supported by the component. */
|
/** Lists the credential types supported by the component. */
|
||||||
protected forwarderOptions$ = new BehaviorSubject<Option<CredentialAlgorithm>[]>([]);
|
protected forwarderOptions$ = new BehaviorSubject<Option<ForwarderNavValue>[]>([]);
|
||||||
|
|
||||||
/** tracks the currently selected credential type */
|
/** tracks the currently selected credential type */
|
||||||
protected algorithm$ = new ReplaySubject<AlgorithmInfo>(1);
|
protected algorithm$ = new ReplaySubject<AlgorithmInfo>(1);
|
||||||
|
@ -201,9 +201,9 @@ export class CredentialGeneratorService {
|
|||||||
algorithms(category: CredentialCategory): AlgorithmInfo[];
|
algorithms(category: CredentialCategory): AlgorithmInfo[];
|
||||||
algorithms(category: CredentialCategory[]): AlgorithmInfo[];
|
algorithms(category: CredentialCategory[]): AlgorithmInfo[];
|
||||||
algorithms(category: CredentialCategory | CredentialCategory[]): AlgorithmInfo[] {
|
algorithms(category: CredentialCategory | CredentialCategory[]): AlgorithmInfo[] {
|
||||||
const categories = Array.isArray(category) ? category : [category];
|
const categories: CredentialCategory[] = Array.isArray(category) ? category : [category];
|
||||||
const algorithms = categories
|
const algorithms = categories
|
||||||
.flatMap((c) => CredentialCategories[c])
|
.flatMap((c) => CredentialCategories[c] as CredentialAlgorithm[])
|
||||||
.map((id) => this.algorithm(id))
|
.map((id) => this.algorithm(id))
|
||||||
.filter((info) => info !== null);
|
.filter((info) => info !== null);
|
||||||
|
|
||||||
|
@ -36,7 +36,7 @@ export const CredentialCategories = Object.freeze({
|
|||||||
username: UsernameAlgorithms as Readonly<UsernameAlgorithm[]>,
|
username: UsernameAlgorithms as Readonly<UsernameAlgorithm[]>,
|
||||||
|
|
||||||
/** Lists algorithms in the "email" credential category */
|
/** Lists algorithms in the "email" credential category */
|
||||||
email: EmailAlgorithms as Readonly<EmailAlgorithm[]>,
|
email: EmailAlgorithms as Readonly<(EmailAlgorithm | ForwarderIntegration)[]>,
|
||||||
});
|
});
|
||||||
|
|
||||||
/** Returns true when the input algorithm is a password algorithm. */
|
/** Returns true when the input algorithm is a password algorithm. */
|
||||||
@ -55,7 +55,7 @@ export function isUsernameAlgorithm(
|
|||||||
|
|
||||||
/** Returns true when the input algorithm is an email algorithm. */
|
/** Returns true when the input algorithm is an email algorithm. */
|
||||||
export function isEmailAlgorithm(algorithm: CredentialAlgorithm): algorithm is EmailAlgorithm {
|
export function isEmailAlgorithm(algorithm: CredentialAlgorithm): algorithm is EmailAlgorithm {
|
||||||
return EmailAlgorithms.includes(algorithm as any);
|
return EmailAlgorithms.includes(algorithm as any) || isForwarderIntegration(algorithm);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** A type of compound credential that may be generated by the credential generator. */
|
/** A type of compound credential that may be generated by the credential generator. */
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { CredentialAlgorithm, PasswordAlgorithm } from "./generator-type";
|
import { EmailAlgorithm, PasswordAlgorithm, UsernameAlgorithm } from "./generator-type";
|
||||||
|
|
||||||
export * from "./boundary";
|
export * from "./boundary";
|
||||||
export * from "./catchall-generator-options";
|
export * from "./catchall-generator-options";
|
||||||
@ -22,7 +22,7 @@ export * from "./word-options";
|
|||||||
/** Provided for backwards compatibility only.
|
/** Provided for backwards compatibility only.
|
||||||
* @deprecated Use one of the Algorithm types instead.
|
* @deprecated Use one of the Algorithm types instead.
|
||||||
*/
|
*/
|
||||||
export type GeneratorType = CredentialAlgorithm;
|
export type GeneratorType = PasswordAlgorithm | UsernameAlgorithm | EmailAlgorithm;
|
||||||
|
|
||||||
/** Provided for backwards compatibility only.
|
/** Provided for backwards compatibility only.
|
||||||
* @deprecated Use one of the Algorithm types instead.
|
* @deprecated Use one of the Algorithm types instead.
|
||||||
|
@ -2,8 +2,10 @@ import { NgModule } from "@angular/core";
|
|||||||
|
|
||||||
import { safeProvider } from "@bitwarden/angular/platform/utils/safe-provider";
|
import { safeProvider } from "@bitwarden/angular/platform/utils/safe-provider";
|
||||||
import { SafeInjectionToken } from "@bitwarden/angular/services/injection-tokens";
|
import { SafeInjectionToken } from "@bitwarden/angular/services/injection-tokens";
|
||||||
|
import { ApiService } from "@bitwarden/common/abstractions/api.service";
|
||||||
import { PolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction";
|
import { PolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction";
|
||||||
import { CryptoService } from "@bitwarden/common/platform/abstractions/crypto.service";
|
import { CryptoService } from "@bitwarden/common/platform/abstractions/crypto.service";
|
||||||
|
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
||||||
import { StateProvider } from "@bitwarden/common/platform/state";
|
import { StateProvider } from "@bitwarden/common/platform/state";
|
||||||
import {
|
import {
|
||||||
createRandomizer,
|
createRandomizer,
|
||||||
@ -32,7 +34,7 @@ const RANDOMIZER = new SafeInjectionToken<Randomizer>("Randomizer");
|
|||||||
safeProvider({
|
safeProvider({
|
||||||
useClass: CredentialGeneratorService,
|
useClass: CredentialGeneratorService,
|
||||||
provide: CredentialGeneratorService,
|
provide: CredentialGeneratorService,
|
||||||
deps: [RANDOMIZER, StateProvider, PolicyService],
|
deps: [RANDOMIZER, StateProvider, PolicyService, ApiService, I18nService],
|
||||||
}),
|
}),
|
||||||
],
|
],
|
||||||
exports: [SendFormComponent],
|
exports: [SendFormComponent],
|
||||||
|
Loading…
Reference in New Issue
Block a user