diff --git a/libs/common/src/enums/feature-flag.enum.ts b/libs/common/src/enums/feature-flag.enum.ts index 7174923f129..bb4a8eb4127 100644 --- a/libs/common/src/enums/feature-flag.enum.ts +++ b/libs/common/src/enums/feature-flag.enum.ts @@ -51,6 +51,7 @@ export enum FeatureFlag { /* Tools */ ItemShare = "item-share", DesktopSendUIRefresh = "desktop-send-ui-refresh", + UseSdkPasswordGenerators = "use-sdk-password-generators", /* Vault */ PM8851_BrowserOnboardingNudge = "pm-8851-browser-onboarding-nudge", @@ -104,6 +105,7 @@ export const DefaultFeatureFlagValue = { /* Tools */ [FeatureFlag.ItemShare]: FALSE, [FeatureFlag.DesktopSendUIRefresh]: FALSE, + [FeatureFlag.UseSdkPasswordGenerators]: FALSE, /* Vault */ [FeatureFlag.PM8851_BrowserOnboardingNudge]: FALSE, diff --git a/libs/common/src/tools/providers.ts b/libs/common/src/tools/providers.ts index a22a22addc5..687a87321b9 100644 --- a/libs/common/src/tools/providers.ts +++ b/libs/common/src/tools/providers.ts @@ -1,4 +1,5 @@ import { PolicyService } from "../admin-console/abstractions/policy/policy.service.abstraction"; +import { ConfigService } from "../platform/abstractions/config/config.service"; import { ExtensionService } from "./extension/extension.service"; import { LogProvider } from "./log"; @@ -13,4 +14,7 @@ export type SystemServiceProvider = { /** Event monitoring and diagnostic interfaces */ readonly log: LogProvider; + + /** Event monitoring and diagnostic interfaces */ + readonly configService: ConfigService; }; diff --git a/libs/tools/generator/core/src/engine/sdk-password-randomizer.ts b/libs/tools/generator/core/src/engine/sdk-password-randomizer.ts index ba125266ec0..03be21eeefb 100644 --- a/libs/tools/generator/core/src/engine/sdk-password-randomizer.ts +++ b/libs/tools/generator/core/src/engine/sdk-password-randomizer.ts @@ -4,6 +4,7 @@ import { PasswordGeneratorRequest, } from "@bitwarden/sdk-internal"; +import { Type } from "../metadata"; import { CredentialGenerator, GenerateRequest, @@ -12,16 +13,20 @@ import { PasswordGenerationOptions, } from "../types"; -/** Generation algorithms that produce randomized secrets */ +/** Generation algorithms that produce randomized secrets by calling on functionality from the SDK */ export class SdkPasswordRandomizer implements CredentialGenerator, CredentialGenerator { /** Instantiates the password randomizer - * @param randomizer data source for random data + * @param client access to SDK client to call upon password/passphrase generation + * @param currentTime gets the current datetime in epoch time */ - constructor(private client: BitwardenClient) {} + constructor( + private client: BitwardenClient, + private currentTime: () => number, + ) {} generate( request: GenerateRequest, @@ -40,8 +45,8 @@ export class SdkPasswordRandomizer return new GeneratedCredential( password, - "password", - Date.now(), + Type.password, + this.currentTime(), request.source, request.website, ); @@ -52,8 +57,8 @@ export class SdkPasswordRandomizer return new GeneratedCredential( passphrase, - "password", - Date.now(), + Type.password, + this.currentTime(), request.source, request.website, ); @@ -65,16 +70,16 @@ export class SdkPasswordRandomizer function convertPasswordRequest(settings: PasswordGenerationOptions): PasswordGeneratorRequest { return { - lowercase: settings.lowercase, - uppercase: settings.uppercase, - numbers: settings.number, - special: settings.special, - length: settings.length, - avoidAmbiguous: settings.ambiguous, - minLowercase: settings.minLowercase, - minUppercase: settings.minUppercase, - minNumber: settings.minNumber, - minSpecial: settings.minSpecial, + lowercase: settings.lowercase!, + uppercase: settings.uppercase!, + numbers: settings.number!, + special: settings.special!, + length: settings.length!, + avoidAmbiguous: settings.ambiguous!, + minLowercase: settings.minLowercase!, + minUppercase: settings.minUppercase!, + minNumber: settings.minNumber!, + minSpecial: settings.minSpecial!, }; } @@ -82,10 +87,10 @@ function convertPassphraseRequest( settings: PassphraseGenerationOptions, ): PassphraseGeneratorRequest { return { - numWords: settings.numWords, - wordSeparator: settings.wordSeparator, - capitalize: settings.capitalize, - includeNumber: settings.includeNumber, + numWords: settings.numWords!, + wordSeparator: settings.wordSeparator!, + capitalize: settings.capitalize!, + includeNumber: settings.includeNumber!, }; } diff --git a/libs/tools/generator/core/src/metadata/data.ts b/libs/tools/generator/core/src/metadata/data.ts index b8b65af5d43..5ac6cac7222 100644 --- a/libs/tools/generator/core/src/metadata/data.ts +++ b/libs/tools/generator/core/src/metadata/data.ts @@ -9,10 +9,10 @@ export const Algorithm = Object.freeze({ passphrase: "passphrase", /** A password composed of random characters, retrieved from SDK */ - sdkPassword: "sdkpassword", + sdkPassword: "sdkPassword", /** A password composed of random words from the EFF word list, retrieved from SDK */ - sdkPassphrase: "sdkpassphrase", + sdkPassphrase: "sdkPassphrase", /** A username composed of words from the EFF word list */ username: "username", diff --git a/libs/tools/generator/core/src/policies/available-algorithms-policy.ts b/libs/tools/generator/core/src/policies/available-algorithms-policy.ts index e63b648cf44..ee97e3598e1 100644 --- a/libs/tools/generator/core/src/policies/available-algorithms-policy.ts +++ b/libs/tools/generator/core/src/policies/available-algorithms-policy.ts @@ -22,7 +22,7 @@ export function availableAlgorithms(policies: Policy[]): CredentialAlgorithm[] { ...AlgorithmsByType[Type.username], ]; if (overridePassword) { - policy.push(overridePassword); + policy.push(overridePassword); //introduce additional password/passphrase stuff } else { policy.push(...AlgorithmsByType[Type.password]); } diff --git a/libs/tools/generator/core/src/providers/generator-metadata-provider.ts b/libs/tools/generator/core/src/providers/generator-metadata-provider.ts index 76e38fd5b50..e28b285496d 100644 --- a/libs/tools/generator/core/src/providers/generator-metadata-provider.ts +++ b/libs/tools/generator/core/src/providers/generator-metadata-provider.ts @@ -2,6 +2,7 @@ import { Observable, combineLatestWith, distinctUntilChanged, + first, map, shareReplay, switchMap, @@ -29,6 +30,8 @@ import { Algorithms, Types, } from "../metadata"; +import sdkPassphrase from "../metadata/password/sdk-eff-word-list"; +import sdkPassword from "../metadata/password/sdk-random-password"; import { availableAlgorithms } from "../policies/available-algorithms-policy"; import { CredentialPreference } from "../types"; import { @@ -41,6 +44,7 @@ import { import { PREFERENCES } from "./credential-preferences"; + /** Surfaces contextual information to credential generators */ export class GeneratorMetadataProvider { /** Instantiates the context provider @@ -83,7 +87,7 @@ export class GeneratorMetadataProvider { result = toForwarderMetadata(extension); } else { - result = this._metadata.get(algorithm); + result = this._metadata.get(algorithm).pipe(first()); } if (!result) { @@ -93,6 +97,25 @@ export class GeneratorMetadataProvider { return result; } + private metadataBySdkFlag( + algorithm: GeneratorMetadata, + useSdkService: boolean, + ): GeneratorMetadata { + if (useSdkService) { + if (algorithm.id == "password") { + return sdkPassword; + } else if (algorithm.id == "passphrase") { + return sdkPassphrase; + } + } + return algorithm; + } + + // metadata$ built by reading config service + // use memoizedMap() to wrap call (creating the map) + // 86 _metadata, new metadata will be encapsulated in observable + // distinctUntilChanged() after memoized map + /** retrieve credential types */ types(): ReadonlyArray { return Types; @@ -148,7 +171,7 @@ export class GeneratorMetadataProvider { const policies$ = this.application.policy .policiesByType$(PolicyType.PasswordGenerator, id) .pipe( - map((p) => availableAlgorithms(p).filter((a) => this._metadata.has(a))), + map((p) => availableAlgorithms(p).filter((a) => this._metadata.has(a))), // filter the list down based on feature flag, withLatestReady to pull in config memoizedMap((p) => new Set(p), { key: (p) => JSON.stringify(p) }), distinctUntilChanged(), // complete policy emissions otherwise `switchMap` holds `available$` open indefinitely