first take on reactive generator component
This commit is contained in:
parent
0868cb8567
commit
6e62fdffd8
|
@ -1,14 +1,13 @@
|
||||||
import { Location } from "@angular/common";
|
import { Location } from "@angular/common";
|
||||||
import { ChangeDetectorRef, Component, NgZone } from "@angular/core";
|
import { Component } from "@angular/core";
|
||||||
import { ActivatedRoute } from "@angular/router";
|
import { ActivatedRoute } from "@angular/router";
|
||||||
import { firstValueFrom } from "rxjs";
|
import { firstValueFrom } from "rxjs";
|
||||||
|
|
||||||
import { GeneratorComponent as BaseGeneratorComponent } from "@bitwarden/angular/tools/generator/components/generator.component";
|
import { GeneratorComponent as BaseGeneratorComponent } from "@bitwarden/angular/tools/generator/components/generator.component";
|
||||||
import { BroadcasterService } from "@bitwarden/common/platform/abstractions/broadcaster.service";
|
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
|
||||||
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
||||||
import { LogService } from "@bitwarden/common/platform/abstractions/log.service";
|
import { LogService } from "@bitwarden/common/platform/abstractions/log.service";
|
||||||
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
|
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
|
||||||
import { StateService } from "@bitwarden/common/platform/abstractions/state.service";
|
|
||||||
import { PasswordGenerationServiceAbstraction } from "@bitwarden/common/tools/generator/password";
|
import { PasswordGenerationServiceAbstraction } from "@bitwarden/common/tools/generator/password";
|
||||||
import { UsernameGenerationServiceAbstraction } from "@bitwarden/common/tools/generator/username";
|
import { UsernameGenerationServiceAbstraction } from "@bitwarden/common/tools/generator/username";
|
||||||
import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service";
|
import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service";
|
||||||
|
@ -29,26 +28,20 @@ export class GeneratorComponent extends BaseGeneratorComponent {
|
||||||
usernameGenerationService: UsernameGenerationServiceAbstraction,
|
usernameGenerationService: UsernameGenerationServiceAbstraction,
|
||||||
platformUtilsService: PlatformUtilsService,
|
platformUtilsService: PlatformUtilsService,
|
||||||
i18nService: I18nService,
|
i18nService: I18nService,
|
||||||
stateService: StateService,
|
accountService: AccountService,
|
||||||
cipherService: CipherService,
|
cipherService: CipherService,
|
||||||
route: ActivatedRoute,
|
route: ActivatedRoute,
|
||||||
logService: LogService,
|
logService: LogService,
|
||||||
broadcasterService: BroadcasterService,
|
|
||||||
ngZone: NgZone,
|
|
||||||
changeDetectorRef: ChangeDetectorRef,
|
|
||||||
private location: Location,
|
private location: Location,
|
||||||
) {
|
) {
|
||||||
super(
|
super(
|
||||||
passwordGenerationService,
|
passwordGenerationService,
|
||||||
usernameGenerationService,
|
usernameGenerationService,
|
||||||
platformUtilsService,
|
platformUtilsService,
|
||||||
stateService,
|
accountService,
|
||||||
i18nService,
|
i18nService,
|
||||||
logService,
|
logService,
|
||||||
route,
|
route,
|
||||||
broadcasterService,
|
|
||||||
ngZone,
|
|
||||||
changeDetectorRef,
|
|
||||||
window,
|
window,
|
||||||
);
|
);
|
||||||
this.cipherService = cipherService;
|
this.cipherService = cipherService;
|
||||||
|
|
|
@ -1,23 +1,13 @@
|
||||||
import {
|
import { Directive, EventEmitter, Input, OnDestroy, OnInit, Output } from "@angular/core";
|
||||||
ChangeDetectorRef,
|
|
||||||
Directive,
|
|
||||||
EventEmitter,
|
|
||||||
Input,
|
|
||||||
NgZone,
|
|
||||||
OnDestroy,
|
|
||||||
OnInit,
|
|
||||||
Output,
|
|
||||||
} from "@angular/core";
|
|
||||||
import { ActivatedRoute } from "@angular/router";
|
import { ActivatedRoute } from "@angular/router";
|
||||||
import { BehaviorSubject } from "rxjs";
|
import { BehaviorSubject, combineLatest, firstValueFrom, Subject } from "rxjs";
|
||||||
import { debounceTime, first, map } from "rxjs/operators";
|
import { debounceTime, first, map, skipWhile, takeUntil } from "rxjs/operators";
|
||||||
|
|
||||||
import { PasswordGeneratorPolicyOptions } from "@bitwarden/common/admin-console/models/domain/password-generator-policy-options";
|
import { PasswordGeneratorPolicyOptions } from "@bitwarden/common/admin-console/models/domain/password-generator-policy-options";
|
||||||
import { BroadcasterService } from "@bitwarden/common/platform/abstractions/broadcaster.service";
|
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
|
||||||
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
||||||
import { LogService } from "@bitwarden/common/platform/abstractions/log.service";
|
import { LogService } from "@bitwarden/common/platform/abstractions/log.service";
|
||||||
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
|
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
|
||||||
import { StateService } from "@bitwarden/common/platform/abstractions/state.service";
|
|
||||||
import { GeneratorType } from "@bitwarden/common/tools/generator/generator-type";
|
import { GeneratorType } from "@bitwarden/common/tools/generator/generator-type";
|
||||||
import {
|
import {
|
||||||
PasswordGenerationServiceAbstraction,
|
PasswordGenerationServiceAbstraction,
|
||||||
|
@ -30,8 +20,6 @@ import {
|
||||||
} from "@bitwarden/common/tools/generator/username";
|
} from "@bitwarden/common/tools/generator/username";
|
||||||
import { EmailForwarderOptions } from "@bitwarden/common/tools/models/domain/email-forwarder-options";
|
import { EmailForwarderOptions } from "@bitwarden/common/tools/models/domain/email-forwarder-options";
|
||||||
|
|
||||||
const ComponentId = "GeneratorComponent";
|
|
||||||
|
|
||||||
@Directive()
|
@Directive()
|
||||||
export class GeneratorComponent implements OnInit, OnDestroy {
|
export class GeneratorComponent implements OnInit, OnDestroy {
|
||||||
@Input() comingFromAddEdit = false;
|
@Input() comingFromAddEdit = false;
|
||||||
|
@ -54,6 +42,9 @@ export class GeneratorComponent implements OnInit, OnDestroy {
|
||||||
enforcedPasswordPolicyOptions: PasswordGeneratorPolicyOptions;
|
enforcedPasswordPolicyOptions: PasswordGeneratorPolicyOptions;
|
||||||
usernameWebsite: string = null;
|
usernameWebsite: string = null;
|
||||||
|
|
||||||
|
private destroy$ = new Subject<void>();
|
||||||
|
private isInitialized$ = new BehaviorSubject(false);
|
||||||
|
|
||||||
// update screen reader minimum password length with 500ms debounce
|
// update screen reader minimum password length with 500ms debounce
|
||||||
// so that the user isn't flooded with status updates
|
// so that the user isn't flooded with status updates
|
||||||
private _passwordOptionsMinLengthForReader = new BehaviorSubject<number>(
|
private _passwordOptionsMinLengthForReader = new BehaviorSubject<number>(
|
||||||
|
@ -68,13 +59,10 @@ export class GeneratorComponent implements OnInit, OnDestroy {
|
||||||
protected passwordGenerationService: PasswordGenerationServiceAbstraction,
|
protected passwordGenerationService: PasswordGenerationServiceAbstraction,
|
||||||
protected usernameGenerationService: UsernameGenerationServiceAbstraction,
|
protected usernameGenerationService: UsernameGenerationServiceAbstraction,
|
||||||
protected platformUtilsService: PlatformUtilsService,
|
protected platformUtilsService: PlatformUtilsService,
|
||||||
protected stateService: StateService,
|
protected accountService: AccountService,
|
||||||
protected i18nService: I18nService,
|
protected i18nService: I18nService,
|
||||||
protected logService: LogService,
|
protected logService: LogService,
|
||||||
protected route: ActivatedRoute,
|
protected route: ActivatedRoute,
|
||||||
protected broadcasterService: BroadcasterService,
|
|
||||||
protected ngZone: NgZone,
|
|
||||||
protected changeDetectorRef: ChangeDetectorRef,
|
|
||||||
private win: Window,
|
private win: Window,
|
||||||
) {
|
) {
|
||||||
this.typeOptions = [
|
this.typeOptions = [
|
||||||
|
@ -105,15 +93,19 @@ export class GeneratorComponent implements OnInit, OnDestroy {
|
||||||
];
|
];
|
||||||
this.subaddressOptions = [{ name: i18nService.t("random"), value: "random" }];
|
this.subaddressOptions = [{ name: i18nService.t("random"), value: "random" }];
|
||||||
this.catchallOptions = [{ name: i18nService.t("random"), value: "random" }];
|
this.catchallOptions = [{ name: i18nService.t("random"), value: "random" }];
|
||||||
// FIXME: Verify that this floating promise is intentional. If it is, add an explanatory comment and ensure there is proper error handling.
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
this.forwardOptions = [
|
||||||
this.initForwardOptions();
|
{ name: "", value: "", validForSelfHosted: false },
|
||||||
|
{ name: "addy.io", value: "anonaddy", validForSelfHosted: true },
|
||||||
|
{ name: "DuckDuckGo", value: "duckduckgo", validForSelfHosted: false },
|
||||||
|
{ name: "Fastmail", value: "fastmail", validForSelfHosted: true },
|
||||||
|
{ name: "Firefox Relay", value: "firefoxrelay", validForSelfHosted: false },
|
||||||
|
{ name: "SimpleLogin", value: "simplelogin", validForSelfHosted: true },
|
||||||
|
{ name: "Forward Email", value: "forwardemail", validForSelfHosted: true },
|
||||||
|
].sort((a, b) => a.name.localeCompare(b.name));
|
||||||
}
|
}
|
||||||
|
|
||||||
async load(navigationType: GeneratorType = undefined) {
|
cascadeOptions(navigationType: GeneratorType = undefined, accountEmail: string) {
|
||||||
const passwordOptionsResponse = await this.passwordGenerationService.getOptions();
|
|
||||||
this.passwordOptions = passwordOptionsResponse[0];
|
|
||||||
this.enforcedPasswordPolicyOptions = passwordOptionsResponse[1];
|
|
||||||
this.avoidAmbiguous = !this.passwordOptions.ambiguous;
|
this.avoidAmbiguous = !this.passwordOptions.ambiguous;
|
||||||
|
|
||||||
if (!this.type) {
|
if (!this.type) {
|
||||||
|
@ -127,7 +119,6 @@ export class GeneratorComponent implements OnInit, OnDestroy {
|
||||||
this.passwordOptions.type =
|
this.passwordOptions.type =
|
||||||
this.passwordOptions.type === "passphrase" ? "passphrase" : "password";
|
this.passwordOptions.type === "passphrase" ? "passphrase" : "password";
|
||||||
|
|
||||||
this.usernameOptions = await this.usernameGenerationService.getOptions();
|
|
||||||
if (this.usernameOptions.type == null) {
|
if (this.usernameOptions.type == null) {
|
||||||
this.usernameOptions.type = "word";
|
this.usernameOptions.type = "word";
|
||||||
}
|
}
|
||||||
|
@ -135,7 +126,7 @@ export class GeneratorComponent implements OnInit, OnDestroy {
|
||||||
this.usernameOptions.subaddressEmail == null ||
|
this.usernameOptions.subaddressEmail == null ||
|
||||||
this.usernameOptions.subaddressEmail === ""
|
this.usernameOptions.subaddressEmail === ""
|
||||||
) {
|
) {
|
||||||
this.usernameOptions.subaddressEmail = await this.stateService.getEmail();
|
this.usernameOptions.subaddressEmail = accountEmail;
|
||||||
}
|
}
|
||||||
if (this.usernameWebsite == null) {
|
if (this.usernameWebsite == null) {
|
||||||
this.usernameOptions.subaddressType = this.usernameOptions.catchallType = "random";
|
this.usernameOptions.subaddressType = this.usernameOptions.catchallType = "random";
|
||||||
|
@ -145,42 +136,69 @@ export class GeneratorComponent implements OnInit, OnDestroy {
|
||||||
this.subaddressOptions.push(websiteOption);
|
this.subaddressOptions.push(websiteOption);
|
||||||
this.catchallOptions.push(websiteOption);
|
this.catchallOptions.push(websiteOption);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.regenerateWithoutButtonPress()) {
|
|
||||||
await this.regenerate();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async ngOnInit() {
|
async ngOnInit() {
|
||||||
// eslint-disable-next-line rxjs/no-async-subscribe
|
// look upon my works, ye mighty, and despair!
|
||||||
this.route.queryParams.pipe(first()).subscribe(async (qParams) => {
|
combineLatest(
|
||||||
await this.load(qParams.type as GeneratorType);
|
this.route.queryParams.pipe(first()),
|
||||||
});
|
this.accountService.activeAccount$.pipe(first()),
|
||||||
|
this.passwordGenerationService.getOptions$(),
|
||||||
|
this.usernameGenerationService.getOptions$(),
|
||||||
|
)
|
||||||
|
.pipe(
|
||||||
|
map(([qParams, account, [passwordOptions, passwordPolicy], usernameOptions]) => ({
|
||||||
|
navigationType: qParams.type as GeneratorType,
|
||||||
|
accountEmail: account.email,
|
||||||
|
passwordOptions,
|
||||||
|
passwordPolicy,
|
||||||
|
usernameOptions,
|
||||||
|
})),
|
||||||
|
takeUntil(this.destroy$),
|
||||||
|
)
|
||||||
|
.subscribe((options) => {
|
||||||
|
this.passwordOptions = options.passwordOptions;
|
||||||
|
this.enforcedPasswordPolicyOptions = options.passwordPolicy;
|
||||||
|
this.usernameOptions = options.usernameOptions;
|
||||||
|
|
||||||
// Load all sends if sync completed in background
|
this.cascadeOptions(options.navigationType, options.accountEmail);
|
||||||
this.broadcasterService.subscribe(ComponentId, (message: any) => {
|
|
||||||
// FIXME: Verify that this floating promise is intentional. If it is, add an explanatory comment and ensure there is proper error handling.
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
|
||||||
this.ngZone.run(async () => {
|
|
||||||
switch (message.command) {
|
|
||||||
case "syncCompleted":
|
|
||||||
window.setTimeout(() => {
|
|
||||||
// FIXME: Verify that this floating promise is intentional. If it is, add an explanatory comment and ensure there is proper error handling.
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
|
||||||
this.load();
|
|
||||||
}, 500);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.changeDetectorRef.detectChanges();
|
this.isInitialized$.next(true);
|
||||||
});
|
});
|
||||||
});
|
|
||||||
|
// only perform this regeneration on the first load to avoid
|
||||||
|
// multiple-generation issues due to `this.regenerate()` calls
|
||||||
|
// elsewhere. The main downside is a generation won't occur
|
||||||
|
// immediately after the policy updates. The user needs to
|
||||||
|
// interact with the generator.
|
||||||
|
this.isInitialized$
|
||||||
|
.pipe(
|
||||||
|
skipWhile((initialized) => !initialized),
|
||||||
|
first(),
|
||||||
|
takeUntil(this.destroy$),
|
||||||
|
)
|
||||||
|
.subscribe(() => {
|
||||||
|
if (this.regenerateWithoutButtonPress()) {
|
||||||
|
this.regenerate().catch((e) => {
|
||||||
|
this.logService.error(e);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// once initialization is complete, `ngOnInit` should return.
|
||||||
|
//
|
||||||
|
// FIXME(#6944): if a sync is in progress, wait to complete until after
|
||||||
|
// the sync completes.
|
||||||
|
await firstValueFrom(
|
||||||
|
this.isInitialized$.pipe(
|
||||||
|
skipWhile((initialized) => !initialized),
|
||||||
|
takeUntil(this.destroy$),
|
||||||
|
),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
ngOnDestroy() {
|
ngOnDestroy() {
|
||||||
this.broadcasterService.unsubscribe(ComponentId);
|
this.destroy$.next();
|
||||||
}
|
}
|
||||||
|
|
||||||
async typeChanged() {
|
async typeChanged() {
|
||||||
|
@ -351,25 +369,4 @@ export class GeneratorComponent implements OnInit, OnDestroy {
|
||||||
|
|
||||||
this._passwordOptionsMinLengthForReader.next(this.passwordOptions.minLength);
|
this._passwordOptionsMinLengthForReader.next(this.passwordOptions.minLength);
|
||||||
}
|
}
|
||||||
|
|
||||||
private async initForwardOptions() {
|
|
||||||
this.forwardOptions = [
|
|
||||||
{ name: "addy.io", value: "anonaddy", validForSelfHosted: true },
|
|
||||||
{ name: "DuckDuckGo", value: "duckduckgo", validForSelfHosted: false },
|
|
||||||
{ name: "Fastmail", value: "fastmail", validForSelfHosted: true },
|
|
||||||
{ name: "Firefox Relay", value: "firefoxrelay", validForSelfHosted: false },
|
|
||||||
{ name: "SimpleLogin", value: "simplelogin", validForSelfHosted: true },
|
|
||||||
{ name: "Forward Email", value: "forwardemail", validForSelfHosted: true },
|
|
||||||
];
|
|
||||||
|
|
||||||
this.usernameOptions = await this.usernameGenerationService.getOptions();
|
|
||||||
if (
|
|
||||||
this.usernameOptions.forwardedService == null ||
|
|
||||||
this.usernameOptions.forwardedService === ""
|
|
||||||
) {
|
|
||||||
this.forwardOptions.push({ name: "", value: null, validForSelfHosted: false });
|
|
||||||
}
|
|
||||||
|
|
||||||
this.forwardOptions = this.forwardOptions.sort((a, b) => a.name.localeCompare(b.name));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
import { Observable } from "rxjs";
|
||||||
|
|
||||||
import { PasswordGeneratorPolicyOptions } from "../../../admin-console/models/domain/password-generator-policy-options";
|
import { PasswordGeneratorPolicyOptions } from "../../../admin-console/models/domain/password-generator-policy-options";
|
||||||
import { GeneratedPasswordHistory } from "../password/generated-password-history";
|
import { GeneratedPasswordHistory } from "../password/generated-password-history";
|
||||||
import { PasswordGeneratorOptions } from "../password/password-generator-options";
|
import { PasswordGeneratorOptions } from "../password/password-generator-options";
|
||||||
|
@ -7,6 +9,7 @@ export abstract class PasswordGenerationServiceAbstraction {
|
||||||
generatePassword: (options: PasswordGeneratorOptions) => Promise<string>;
|
generatePassword: (options: PasswordGeneratorOptions) => Promise<string>;
|
||||||
generatePassphrase: (options: PasswordGeneratorOptions) => Promise<string>;
|
generatePassphrase: (options: PasswordGeneratorOptions) => Promise<string>;
|
||||||
getOptions: () => Promise<[PasswordGeneratorOptions, PasswordGeneratorPolicyOptions]>;
|
getOptions: () => Promise<[PasswordGeneratorOptions, PasswordGeneratorPolicyOptions]>;
|
||||||
|
getOptions$: () => Observable<[PasswordGeneratorOptions, PasswordGeneratorPolicyOptions]>;
|
||||||
enforcePasswordGeneratorPoliciesOnOptions: (
|
enforcePasswordGeneratorPoliciesOnOptions: (
|
||||||
options: PasswordGeneratorOptions,
|
options: PasswordGeneratorOptions,
|
||||||
) => Promise<[PasswordGeneratorOptions, PasswordGeneratorPolicyOptions]>;
|
) => Promise<[PasswordGeneratorOptions, PasswordGeneratorPolicyOptions]>;
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
import { Observable } from "rxjs";
|
||||||
|
|
||||||
import { UsernameGeneratorOptions } from "../username/username-generation-options";
|
import { UsernameGeneratorOptions } from "../username/username-generation-options";
|
||||||
|
|
||||||
/** @deprecated Use {@link GeneratorService} with a username {@link GeneratorStrategy} instead. */
|
/** @deprecated Use {@link GeneratorService} with a username {@link GeneratorStrategy} instead. */
|
||||||
|
@ -8,5 +10,6 @@ export abstract class UsernameGenerationServiceAbstraction {
|
||||||
generateCatchall: (options: UsernameGeneratorOptions) => Promise<string>;
|
generateCatchall: (options: UsernameGeneratorOptions) => Promise<string>;
|
||||||
generateForwarded: (options: UsernameGeneratorOptions) => Promise<string>;
|
generateForwarded: (options: UsernameGeneratorOptions) => Promise<string>;
|
||||||
getOptions: () => Promise<UsernameGeneratorOptions>;
|
getOptions: () => Promise<UsernameGeneratorOptions>;
|
||||||
|
getOptions$: () => Observable<UsernameGeneratorOptions>;
|
||||||
saveOptions: (options: UsernameGeneratorOptions) => Promise<void>;
|
saveOptions: (options: UsernameGeneratorOptions) => Promise<void>;
|
||||||
}
|
}
|
||||||
|
|
|
@ -99,7 +99,7 @@ export class LegacyPasswordGenerationService implements PasswordGenerationServic
|
||||||
return this.passphrases.generate(options);
|
return this.passphrases.generate(options);
|
||||||
}
|
}
|
||||||
|
|
||||||
async getOptions() {
|
getOptions$() {
|
||||||
const options$ = this.accountService.activeAccount$.pipe(
|
const options$ = this.accountService.activeAccount$.pipe(
|
||||||
concatMap((activeUser) =>
|
concatMap((activeUser) =>
|
||||||
zip(
|
zip(
|
||||||
|
@ -127,9 +127,9 @@ export class LegacyPasswordGenerationService implements PasswordGenerationServic
|
||||||
generatorEvaluator,
|
generatorEvaluator,
|
||||||
]) => {
|
]) => {
|
||||||
const options = this.toPasswordGeneratorOptions({
|
const options = this.toPasswordGeneratorOptions({
|
||||||
password: passwordOptions ?? passwordDefaults,
|
password: passwordEvaluator.applyPolicy(passwordOptions ?? passwordDefaults),
|
||||||
passphrase: passphraseOptions ?? passphraseDefaults,
|
passphrase: passphraseEvaluator.applyPolicy(passphraseOptions ?? passphraseDefaults),
|
||||||
generator: generatorOptions ?? generatorDefaults,
|
generator: generatorEvaluator.applyPolicy(generatorOptions ?? generatorDefaults),
|
||||||
});
|
});
|
||||||
|
|
||||||
const policy = Object.assign(
|
const policy = Object.assign(
|
||||||
|
@ -144,8 +144,11 @@ export class LegacyPasswordGenerationService implements PasswordGenerationServic
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
const options = await firstValueFrom(options$);
|
return options$;
|
||||||
return options;
|
}
|
||||||
|
|
||||||
|
async getOptions() {
|
||||||
|
return await firstValueFrom(this.getOptions$());
|
||||||
}
|
}
|
||||||
|
|
||||||
async enforcePasswordGeneratorPoliciesOnOptions(options: PasswordGeneratorOptions) {
|
async enforcePasswordGeneratorPoliciesOnOptions(options: PasswordGeneratorOptions) {
|
||||||
|
|
|
@ -205,7 +205,7 @@ export class LegacyUsernameGenerationService implements UsernameGenerationServic
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
getOptions() {
|
getOptions$() {
|
||||||
const options$ = this.accountService.activeAccount$.pipe(
|
const options$ = this.accountService.activeAccount$.pipe(
|
||||||
concatMap((account) =>
|
concatMap((account) =>
|
||||||
zip(
|
zip(
|
||||||
|
@ -273,7 +273,11 @@ export class LegacyUsernameGenerationService implements UsernameGenerationServic
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
return firstValueFrom(options$);
|
return options$;
|
||||||
|
}
|
||||||
|
|
||||||
|
getOptions() {
|
||||||
|
return firstValueFrom(this.getOptions$());
|
||||||
}
|
}
|
||||||
|
|
||||||
async saveOptions(options: UsernameGeneratorOptions) {
|
async saveOptions(options: UsernameGeneratorOptions) {
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
import { from } from "rxjs";
|
||||||
|
|
||||||
import { PolicyService } from "../../../admin-console/abstractions/policy/policy.service.abstraction";
|
import { PolicyService } from "../../../admin-console/abstractions/policy/policy.service.abstraction";
|
||||||
import { PolicyType } from "../../../admin-console/enums";
|
import { PolicyType } from "../../../admin-console/enums";
|
||||||
import { PasswordGeneratorPolicyOptions } from "../../../admin-console/models/domain/password-generator-policy-options";
|
import { PasswordGeneratorPolicyOptions } from "../../../admin-console/models/domain/password-generator-policy-options";
|
||||||
|
@ -171,6 +173,10 @@ export class PasswordGenerationService implements PasswordGenerationServiceAbstr
|
||||||
return wordList.join(o.wordSeparator);
|
return wordList.join(o.wordSeparator);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getOptions$() {
|
||||||
|
return from(this.getOptions());
|
||||||
|
}
|
||||||
|
|
||||||
async getOptions(): Promise<[PasswordGeneratorOptions, PasswordGeneratorPolicyOptions]> {
|
async getOptions(): Promise<[PasswordGeneratorOptions, PasswordGeneratorPolicyOptions]> {
|
||||||
let options = await this.stateService.getPasswordGenerationOptions();
|
let options = await this.stateService.getPasswordGenerationOptions();
|
||||||
if (options == null) {
|
if (options == null) {
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
import { from } from "rxjs";
|
||||||
|
|
||||||
import { ApiService } from "../../../abstractions/api.service";
|
import { ApiService } from "../../../abstractions/api.service";
|
||||||
import { CryptoService } from "../../../platform/abstractions/crypto.service";
|
import { CryptoService } from "../../../platform/abstractions/crypto.service";
|
||||||
import { StateService } from "../../../platform/abstractions/state.service";
|
import { StateService } from "../../../platform/abstractions/state.service";
|
||||||
|
@ -158,6 +160,10 @@ export class UsernameGenerationService implements UsernameGenerationServiceAbstr
|
||||||
return forwarder.generate(this.apiService, forwarderOptions);
|
return forwarder.generate(this.apiService, forwarderOptions);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getOptions$() {
|
||||||
|
return from(this.getOptions());
|
||||||
|
}
|
||||||
|
|
||||||
async getOptions(): Promise<UsernameGeneratorOptions> {
|
async getOptions(): Promise<UsernameGeneratorOptions> {
|
||||||
let options = await this.stateService.getUsernameGenerationOptions();
|
let options = await this.stateService.getUsernameGenerationOptions();
|
||||||
if (options == null) {
|
if (options == null) {
|
||||||
|
|
Loading…
Reference in New Issue