1
0
mirror of https://github.com/bitwarden/browser.git synced 2024-10-22 07:50:04 +02:00

localize algorithm names and descriptions in the credential generator service

This commit is contained in:
✨ Audrey ✨ 2024-10-10 13:57:36 -04:00
parent 3aebbe9a64
commit b79d4c12f1
No known key found for this signature in database
GPG Key ID: 0CF8B4C0D9088B97
5 changed files with 77 additions and 30 deletions

View File

@ -19,9 +19,9 @@ import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.servic
import { UserId } from "@bitwarden/common/types/guid";
import { Option } from "@bitwarden/components/src/select/option";
import {
AlgorithmInfo,
CredentialAlgorithm,
CredentialCategory,
CredentialGeneratorInfo,
CredentialGeneratorService,
GeneratedCredential,
Generators,
@ -114,7 +114,7 @@ export class CredentialGeneratorComponent implements OnInit, OnDestroy {
this.algorithm$
.pipe(
map((a) => a?.descriptionKey && this.i18nService.t(a?.descriptionKey)),
map((a) => a?.description),
takeUntil(this.destroyed),
)
.subscribe((hint) => {
@ -268,7 +268,7 @@ export class CredentialGeneratorComponent implements OnInit, OnDestroy {
protected rootOptions$ = new BehaviorSubject<Option<RootNavValue>[]>([]);
/** tracks the currently selected credential type */
protected algorithm$ = new ReplaySubject<CredentialGeneratorInfo>(1);
protected algorithm$ = new ReplaySubject<AlgorithmInfo>(1);
/** Emits hint key for the currently selected credential type */
protected credentialTypeHint$ = new ReplaySubject<string>(1);
@ -285,10 +285,10 @@ export class CredentialGeneratorComponent implements OnInit, OnDestroy {
/** Emits when a new credential is requested */
protected readonly generate$ = new Subject<void>();
private toOptions(algorithms: CredentialGeneratorInfo[]) {
private toOptions(algorithms: AlgorithmInfo[]) {
const options: Option<CredentialAlgorithm>[] = algorithms.map((algorithm) => ({
value: algorithm.id,
label: this.i18nService.t(algorithm.nameKey),
label: this.i18nService.t(algorithm.name),
}));
return options;

View File

@ -20,9 +20,9 @@ import {
Generators,
PasswordAlgorithm,
GeneratedCredential,
CredentialGeneratorInfo,
CredentialAlgorithm,
isPasswordAlgorithm,
AlgorithmInfo,
} from "@bitwarden/generator-core";
/** Options group for passwords */
@ -174,12 +174,12 @@ export class PasswordGeneratorComponent implements OnInit, OnDestroy {
protected passwordOptions$ = new BehaviorSubject<Option<CredentialAlgorithm>[]>([]);
/** tracks the currently selected credential type */
protected algorithm$ = new ReplaySubject<CredentialGeneratorInfo>(1);
protected algorithm$ = new ReplaySubject<AlgorithmInfo>(1);
private toOptions(algorithms: CredentialGeneratorInfo[]) {
private toOptions(algorithms: AlgorithmInfo[]) {
const options: Option<CredentialAlgorithm>[] = algorithms.map((algorithm) => ({
value: algorithm.id,
label: this.i18nService.t(algorithm.nameKey),
label: this.i18nService.t(algorithm.name),
}));
return options;

View File

@ -17,8 +17,8 @@ import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.servic
import { UserId } from "@bitwarden/common/types/guid";
import { Option } from "@bitwarden/components/src/select/option";
import {
AlgorithmInfo,
CredentialAlgorithm,
CredentialGeneratorInfo,
CredentialGeneratorService,
GeneratedCredential,
Generators,
@ -97,7 +97,7 @@ export class UsernameGeneratorComponent implements OnInit, OnDestroy {
this.algorithm$
.pipe(
map((a) => a?.descriptionKey && this.i18nService.t(a?.descriptionKey)),
map((a) => a?.description),
takeUntil(this.destroyed),
)
.subscribe((hint) => {
@ -205,7 +205,7 @@ export class UsernameGeneratorComponent implements OnInit, OnDestroy {
protected forwarderOptions$ = new BehaviorSubject<Option<CredentialAlgorithm>[]>([]);
/** tracks the currently selected credential type */
protected algorithm$ = new ReplaySubject<CredentialGeneratorInfo>(1);
protected algorithm$ = new ReplaySubject<AlgorithmInfo>(1);
/** Emits hint key for the currently selected credential type */
protected credentialTypeHint$ = new ReplaySubject<string>(1);
@ -219,10 +219,10 @@ export class UsernameGeneratorComponent implements OnInit, OnDestroy {
/** Emits when a new credential is requested */
protected readonly generate$ = new Subject<void>();
private toOptions(algorithms: CredentialGeneratorInfo[]) {
private toOptions(algorithms: AlgorithmInfo[]) {
const options: Option<CredentialAlgorithm>[] = algorithms.map((algorithm) => ({
value: algorithm.id,
label: this.i18nService.t(algorithm.nameKey),
label: this.i18nService.t(algorithm.name),
}));
return options;

View File

@ -30,7 +30,7 @@ import {
SingleUserDependency,
UserDependency,
} from "@bitwarden/common/tools/dependencies";
import { IntegrationId } from "@bitwarden/common/tools/integration";
import { IntegrationId, IntegrationMetadata } from "@bitwarden/common/tools/integration";
import { RestClient } from "@bitwarden/common/tools/integration/rpc";
import { isDynamic } from "@bitwarden/common/tools/state/state-constraints-dependency";
import { UserStateSubject } from "@bitwarden/common/tools/state/user-state-subject";
@ -43,12 +43,13 @@ import {
CredentialAlgorithm,
CredentialCategories,
CredentialCategory,
CredentialGeneratorInfo,
AlgorithmInfo,
CredentialPreference,
isForwarderIntegration,
} from "../types";
import {
CredentialGeneratorConfiguration as Configuration,
CredentialGeneratorInfo,
GeneratorDependencyProvider,
} from "../types/credential-generator-configuration";
import { GeneratorConstraints } from "../types/generator-constraints";
@ -152,11 +153,11 @@ export class CredentialGeneratorService {
algorithms$(
category: CredentialCategory,
dependencies?: Algorithms$Dependencies,
): Observable<CredentialGeneratorInfo[]>;
): Observable<AlgorithmInfo[]>;
algorithms$(
category: CredentialCategory[],
dependencies?: Algorithms$Dependencies,
): Observable<CredentialGeneratorInfo[]>;
): Observable<AlgorithmInfo[]>;
algorithms$(
category: CredentialCategory | CredentialCategory[],
dependencies?: Algorithms$Dependencies,
@ -197,9 +198,9 @@ export class CredentialGeneratorService {
* @param category the category or categories of interest
* @returns A list containing the requested metadata.
*/
algorithms(category: CredentialCategory): CredentialGeneratorInfo[];
algorithms(category: CredentialCategory[]): CredentialGeneratorInfo[];
algorithms(category: CredentialCategory | CredentialCategory[]): CredentialGeneratorInfo[] {
algorithms(category: CredentialCategory): AlgorithmInfo[];
algorithms(category: CredentialCategory[]): AlgorithmInfo[];
algorithms(category: CredentialCategory | CredentialCategory[]): AlgorithmInfo[] {
const categories = Array.isArray(category) ? category : [category];
const algorithms = categories
.flatMap((c) => CredentialCategories[c])
@ -213,18 +214,37 @@ export class CredentialGeneratorService {
* @param id identifies the algorithm
* @returns the requested metadata, or `null` if the metadata wasn't found.
*/
algorithm(id: CredentialAlgorithm): CredentialGeneratorInfo {
if (isForwarderIntegration(id)) {
const forwarder = getForwarderConfiguration(id.forwarder);
if (!forwarder) {
throw new Error(`Invalid forwarder id: ${id.forwarder}`);
}
algorithm(id: CredentialAlgorithm): AlgorithmInfo {
let generator: CredentialGeneratorInfo = null;
let integration: IntegrationMetadata = null;
const generator = toCredentialGeneratorConfiguration(forwarder);
return generator;
if (isForwarderIntegration(id)) {
const forwarderConfig = getForwarderConfiguration(id.forwarder);
integration = forwarderConfig;
if (forwarderConfig) {
generator = toCredentialGeneratorConfiguration(forwarderConfig);
}
} else {
return Generators[id];
generator = Generators[id];
}
if (!generator) {
throw new Error(`Invalid credential algorithm: ${JSON.stringify(id)}`);
}
const info: AlgorithmInfo = {
id: generator.id,
category: generator.category,
name: integration ? integration.name : this.i18nService.t(generator.nameKey),
onlyOnRequest: generator.onlyOnRequest,
};
if (generator.descriptionKey) {
info.description = this.i18nService.t(generator.descriptionKey);
}
return info;
}
/** Get the settings for the provided configuration

View File

@ -14,6 +14,33 @@ export type GeneratorDependencyProvider = {
i18nService: I18nService;
};
export type AlgorithmInfo = {
/** Uniquely identifies the credential configuration
* @example
* // Use `isForwarderIntegration(algorithm: CredentialAlgorithm)`
* // to pattern test whether the credential describes a forwarder algorithm
* const meta : CredentialGeneratorInfo = // ...
* const { forwarder } = isForwarderIntegration(meta.id) ? credentialId : {};
*/
id: CredentialAlgorithm;
/** The kind of credential generated by this configuration */
category: CredentialCategory;
/** Localized algorithm name */
name: string;
/** Localized algorithm description */
description?: string;
/** When true, credential generation must be explicitly requested.
* @remarks this property is useful when credential generation
* carries side effects, such as configuring a service external
* to Bitwarden.
*/
onlyOnRequest: boolean;
};
/** Credential generator metadata common across credential generators */
export type CredentialGeneratorInfo = {
/** Uniquely identifies the credential configuration