mirror of
https://github.com/bitwarden/browser
synced 2025-12-12 14:23:32 +00:00
[PM-19976] Implement SDK generator engines (#15063)
* Hook up sdk engines to feature flag --------- Co-authored-by: ✨ Audrey ✨ <ajensen@bitwarden.com>
This commit is contained in:
@@ -44,6 +44,7 @@ export enum FeatureFlag {
|
|||||||
|
|
||||||
/* Tools */
|
/* Tools */
|
||||||
DesktopSendUIRefresh = "desktop-send-ui-refresh",
|
DesktopSendUIRefresh = "desktop-send-ui-refresh",
|
||||||
|
UseSdkPasswordGenerators = "pm-19976-use-sdk-password-generators",
|
||||||
|
|
||||||
/* DIRT */
|
/* DIRT */
|
||||||
EventBasedOrganizationIntegrations = "event-based-organization-integrations",
|
EventBasedOrganizationIntegrations = "event-based-organization-integrations",
|
||||||
@@ -90,6 +91,7 @@ export const DefaultFeatureFlagValue = {
|
|||||||
|
|
||||||
/* Tools */
|
/* Tools */
|
||||||
[FeatureFlag.DesktopSendUIRefresh]: FALSE,
|
[FeatureFlag.DesktopSendUIRefresh]: FALSE,
|
||||||
|
[FeatureFlag.UseSdkPasswordGenerators]: FALSE,
|
||||||
|
|
||||||
/* DIRT */
|
/* DIRT */
|
||||||
[FeatureFlag.EventBasedOrganizationIntegrations]: FALSE,
|
[FeatureFlag.EventBasedOrganizationIntegrations]: FALSE,
|
||||||
|
|||||||
@@ -1,4 +1,7 @@
|
|||||||
|
import { BitwardenClient } from "@bitwarden/sdk-internal";
|
||||||
|
|
||||||
import { PolicyService } from "../admin-console/abstractions/policy/policy.service.abstraction";
|
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 { ExtensionService } from "./extension/extension.service";
|
||||||
import { LogProvider } from "./log";
|
import { LogProvider } from "./log";
|
||||||
@@ -13,4 +16,10 @@ export type SystemServiceProvider = {
|
|||||||
|
|
||||||
/** Event monitoring and diagnostic interfaces */
|
/** Event monitoring and diagnostic interfaces */
|
||||||
readonly log: LogProvider;
|
readonly log: LogProvider;
|
||||||
|
|
||||||
|
/** Config Service to determine flag features */
|
||||||
|
readonly configService: ConfigService;
|
||||||
|
|
||||||
|
/** SDK Service */
|
||||||
|
readonly sdk: BitwardenClient;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,11 +1,14 @@
|
|||||||
import { NgModule } from "@angular/core";
|
import { NgModule } from "@angular/core";
|
||||||
|
import { from, take } from "rxjs";
|
||||||
|
|
||||||
import { JslibModule } from "@bitwarden/angular/jslib.module";
|
import { JslibModule } from "@bitwarden/angular/jslib.module";
|
||||||
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 { 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 { FeatureFlag } from "@bitwarden/common/enums/feature-flag.enum";
|
||||||
import { EncryptService } from "@bitwarden/common/key-management/crypto/abstractions/encrypt.service";
|
import { EncryptService } from "@bitwarden/common/key-management/crypto/abstractions/encrypt.service";
|
||||||
|
import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.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";
|
||||||
@@ -83,6 +86,7 @@ const SYSTEM_SERVICE_PROVIDER = new SafeInjectionToken<SystemServiceProvider>("S
|
|||||||
registry: ExtensionRegistry,
|
registry: ExtensionRegistry,
|
||||||
logger: LogService,
|
logger: LogService,
|
||||||
environment: PlatformUtilsService,
|
environment: PlatformUtilsService,
|
||||||
|
configService: ConfigService,
|
||||||
) => {
|
) => {
|
||||||
let log: LogProvider;
|
let log: LogProvider;
|
||||||
if (environment.isDev()) {
|
if (environment.isDev()) {
|
||||||
@@ -102,6 +106,7 @@ const SYSTEM_SERVICE_PROVIDER = new SafeInjectionToken<SystemServiceProvider>("S
|
|||||||
policy,
|
policy,
|
||||||
extension,
|
extension,
|
||||||
log,
|
log,
|
||||||
|
configService,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
deps: [
|
deps: [
|
||||||
@@ -111,6 +116,7 @@ const SYSTEM_SERVICE_PROVIDER = new SafeInjectionToken<SystemServiceProvider>("S
|
|||||||
ExtensionRegistry,
|
ExtensionRegistry,
|
||||||
LogService,
|
LogService,
|
||||||
PlatformUtilsService,
|
PlatformUtilsService,
|
||||||
|
ConfigService,
|
||||||
],
|
],
|
||||||
}),
|
}),
|
||||||
safeProvider({
|
safeProvider({
|
||||||
@@ -130,17 +136,26 @@ const SYSTEM_SERVICE_PROVIDER = new SafeInjectionToken<SystemServiceProvider>("S
|
|||||||
now: Date.now,
|
now: Date.now,
|
||||||
} satisfies UserStateSubjectDependencyProvider;
|
} satisfies UserStateSubjectDependencyProvider;
|
||||||
|
|
||||||
|
const featureFlagObs$ = from(
|
||||||
|
system.configService.getFeatureFlag(FeatureFlag.UseSdkPasswordGenerators),
|
||||||
|
);
|
||||||
|
let featureFlag: boolean = false;
|
||||||
|
featureFlagObs$.pipe(take(1)).subscribe((ff) => (featureFlag = ff));
|
||||||
const metadata = new providers.GeneratorMetadataProvider(
|
const metadata = new providers.GeneratorMetadataProvider(
|
||||||
userStateDeps,
|
userStateDeps,
|
||||||
system,
|
system,
|
||||||
Object.values(BuiltIn),
|
Object.values(BuiltIn),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const sdkService = featureFlag ? system.sdk : undefined;
|
||||||
const profile = new providers.GeneratorProfileProvider(userStateDeps, system.policy);
|
const profile = new providers.GeneratorProfileProvider(userStateDeps, system.policy);
|
||||||
|
|
||||||
const generator: providers.GeneratorDependencyProvider = {
|
const generator: providers.GeneratorDependencyProvider = {
|
||||||
randomizer: random,
|
randomizer: random,
|
||||||
client: new RestClient(api, i18n),
|
client: new RestClient(api, i18n),
|
||||||
i18nService: i18n,
|
i18nService: i18n,
|
||||||
|
sdk: sdkService,
|
||||||
|
now: Date.now,
|
||||||
};
|
};
|
||||||
|
|
||||||
const userState: UserStateSubjectDependencyProvider = {
|
const userState: UserStateSubjectDependencyProvider = {
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ describe("PasswordRandomizer", () => {
|
|||||||
|
|
||||||
describe("randomAscii", () => {
|
describe("randomAscii", () => {
|
||||||
it("returns the empty string when no character sets are specified", async () => {
|
it("returns the empty string when no character sets are specified", async () => {
|
||||||
const password = new PasswordRandomizer(randomizer);
|
const password = new PasswordRandomizer(randomizer, Date.now);
|
||||||
|
|
||||||
const result = await password.randomAscii({
|
const result = await password.randomAscii({
|
||||||
all: 1,
|
all: 1,
|
||||||
@@ -41,7 +41,7 @@ describe("PasswordRandomizer", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it("generates an uppercase ascii password", async () => {
|
it("generates an uppercase ascii password", async () => {
|
||||||
const password = new PasswordRandomizer(randomizer);
|
const password = new PasswordRandomizer(randomizer, Date.now);
|
||||||
|
|
||||||
const result = await password.randomAscii({
|
const result = await password.randomAscii({
|
||||||
all: 0,
|
all: 0,
|
||||||
@@ -54,7 +54,7 @@ describe("PasswordRandomizer", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it("generates an uppercase ascii password without ambiguous characters", async () => {
|
it("generates an uppercase ascii password without ambiguous characters", async () => {
|
||||||
const password = new PasswordRandomizer(randomizer);
|
const password = new PasswordRandomizer(randomizer, Date.now);
|
||||||
|
|
||||||
const result = await password.randomAscii({
|
const result = await password.randomAscii({
|
||||||
all: 0,
|
all: 0,
|
||||||
@@ -67,7 +67,7 @@ describe("PasswordRandomizer", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it("generates a lowercase ascii password", async () => {
|
it("generates a lowercase ascii password", async () => {
|
||||||
const password = new PasswordRandomizer(randomizer);
|
const password = new PasswordRandomizer(randomizer, Date.now);
|
||||||
|
|
||||||
const result = await password.randomAscii({
|
const result = await password.randomAscii({
|
||||||
all: 0,
|
all: 0,
|
||||||
@@ -80,7 +80,7 @@ describe("PasswordRandomizer", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it("generates a lowercase ascii password without ambiguous characters", async () => {
|
it("generates a lowercase ascii password without ambiguous characters", async () => {
|
||||||
const password = new PasswordRandomizer(randomizer);
|
const password = new PasswordRandomizer(randomizer, Date.now);
|
||||||
|
|
||||||
const result = await password.randomAscii({
|
const result = await password.randomAscii({
|
||||||
all: 0,
|
all: 0,
|
||||||
@@ -93,7 +93,7 @@ describe("PasswordRandomizer", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it("generates a numeric ascii password", async () => {
|
it("generates a numeric ascii password", async () => {
|
||||||
const password = new PasswordRandomizer(randomizer);
|
const password = new PasswordRandomizer(randomizer, Date.now);
|
||||||
|
|
||||||
const result = await password.randomAscii({
|
const result = await password.randomAscii({
|
||||||
all: 0,
|
all: 0,
|
||||||
@@ -106,7 +106,7 @@ describe("PasswordRandomizer", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it("generates a numeric password without ambiguous characters", async () => {
|
it("generates a numeric password without ambiguous characters", async () => {
|
||||||
const password = new PasswordRandomizer(randomizer);
|
const password = new PasswordRandomizer(randomizer, Date.now);
|
||||||
|
|
||||||
const result = await password.randomAscii({
|
const result = await password.randomAscii({
|
||||||
all: 0,
|
all: 0,
|
||||||
@@ -119,7 +119,7 @@ describe("PasswordRandomizer", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it("generates a special character password", async () => {
|
it("generates a special character password", async () => {
|
||||||
const password = new PasswordRandomizer(randomizer);
|
const password = new PasswordRandomizer(randomizer, Date.now);
|
||||||
|
|
||||||
const result = await password.randomAscii({
|
const result = await password.randomAscii({
|
||||||
all: 0,
|
all: 0,
|
||||||
@@ -132,7 +132,7 @@ describe("PasswordRandomizer", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it("generates a special character password without ambiguous characters", async () => {
|
it("generates a special character password without ambiguous characters", async () => {
|
||||||
const password = new PasswordRandomizer(randomizer);
|
const password = new PasswordRandomizer(randomizer, Date.now);
|
||||||
|
|
||||||
const result = await password.randomAscii({
|
const result = await password.randomAscii({
|
||||||
all: 0,
|
all: 0,
|
||||||
@@ -148,7 +148,7 @@ describe("PasswordRandomizer", () => {
|
|||||||
[2, "AA"],
|
[2, "AA"],
|
||||||
[3, "AAA"],
|
[3, "AAA"],
|
||||||
])("includes %p uppercase characters", async (uppercase, expected) => {
|
])("includes %p uppercase characters", async (uppercase, expected) => {
|
||||||
const password = new PasswordRandomizer(randomizer);
|
const password = new PasswordRandomizer(randomizer, Date.now);
|
||||||
|
|
||||||
const result = await password.randomAscii({
|
const result = await password.randomAscii({
|
||||||
all: 0,
|
all: 0,
|
||||||
@@ -163,7 +163,7 @@ describe("PasswordRandomizer", () => {
|
|||||||
[2, "aa"],
|
[2, "aa"],
|
||||||
[3, "aaa"],
|
[3, "aaa"],
|
||||||
])("includes %p lowercase characters", async (lowercase, expected) => {
|
])("includes %p lowercase characters", async (lowercase, expected) => {
|
||||||
const password = new PasswordRandomizer(randomizer);
|
const password = new PasswordRandomizer(randomizer, Date.now);
|
||||||
|
|
||||||
const result = await password.randomAscii({
|
const result = await password.randomAscii({
|
||||||
all: 0,
|
all: 0,
|
||||||
@@ -178,7 +178,7 @@ describe("PasswordRandomizer", () => {
|
|||||||
[2, "00"],
|
[2, "00"],
|
||||||
[3, "000"],
|
[3, "000"],
|
||||||
])("includes %p digits", async (digits, expected) => {
|
])("includes %p digits", async (digits, expected) => {
|
||||||
const password = new PasswordRandomizer(randomizer);
|
const password = new PasswordRandomizer(randomizer, Date.now);
|
||||||
|
|
||||||
const result = await password.randomAscii({
|
const result = await password.randomAscii({
|
||||||
all: 0,
|
all: 0,
|
||||||
@@ -193,7 +193,7 @@ describe("PasswordRandomizer", () => {
|
|||||||
[2, "!!"],
|
[2, "!!"],
|
||||||
[3, "!!!"],
|
[3, "!!!"],
|
||||||
])("includes %p special characters", async (special, expected) => {
|
])("includes %p special characters", async (special, expected) => {
|
||||||
const password = new PasswordRandomizer(randomizer);
|
const password = new PasswordRandomizer(randomizer, Date.now);
|
||||||
|
|
||||||
const result = await password.randomAscii({
|
const result = await password.randomAscii({
|
||||||
all: 0,
|
all: 0,
|
||||||
@@ -212,7 +212,7 @@ describe("PasswordRandomizer", () => {
|
|||||||
])(
|
])(
|
||||||
"mixes character sets for the remaining characters (=%p)",
|
"mixes character sets for the remaining characters (=%p)",
|
||||||
async (setting: Partial<RandomAsciiRequest>, set: CharacterSet) => {
|
async (setting: Partial<RandomAsciiRequest>, set: CharacterSet) => {
|
||||||
const password = new PasswordRandomizer(randomizer);
|
const password = new PasswordRandomizer(randomizer, Date.now);
|
||||||
|
|
||||||
await password.randomAscii({
|
await password.randomAscii({
|
||||||
...setting,
|
...setting,
|
||||||
@@ -225,7 +225,7 @@ describe("PasswordRandomizer", () => {
|
|||||||
);
|
);
|
||||||
|
|
||||||
it("shuffles the password characters", async () => {
|
it("shuffles the password characters", async () => {
|
||||||
const password = new PasswordRandomizer(randomizer);
|
const password = new PasswordRandomizer(randomizer, Date.now);
|
||||||
|
|
||||||
// Typically `shuffle` randomizes the order of the array it's been
|
// Typically `shuffle` randomizes the order of the array it's been
|
||||||
// given. In the password generator, the array is generated from the
|
// given. In the password generator, the array is generated from the
|
||||||
@@ -247,7 +247,7 @@ describe("PasswordRandomizer", () => {
|
|||||||
|
|
||||||
describe("randomEffLongWords", () => {
|
describe("randomEffLongWords", () => {
|
||||||
it("generates the empty string when no words are passed", async () => {
|
it("generates the empty string when no words are passed", async () => {
|
||||||
const password = new PasswordRandomizer(randomizer);
|
const password = new PasswordRandomizer(randomizer, Date.now);
|
||||||
|
|
||||||
const result = await password.randomEffLongWords({
|
const result = await password.randomEffLongWords({
|
||||||
numberOfWords: 0,
|
numberOfWords: 0,
|
||||||
@@ -263,7 +263,7 @@ describe("PasswordRandomizer", () => {
|
|||||||
[1, "foo"],
|
[1, "foo"],
|
||||||
[2, "foofoo"],
|
[2, "foofoo"],
|
||||||
])("generates a %i-length word list", async (words, expected) => {
|
])("generates a %i-length word list", async (words, expected) => {
|
||||||
const password = new PasswordRandomizer(randomizer);
|
const password = new PasswordRandomizer(randomizer, Date.now);
|
||||||
|
|
||||||
const result = await password.randomEffLongWords({
|
const result = await password.randomEffLongWords({
|
||||||
numberOfWords: words,
|
numberOfWords: words,
|
||||||
@@ -280,7 +280,7 @@ describe("PasswordRandomizer", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it("capitalizes the word list", async () => {
|
it("capitalizes the word list", async () => {
|
||||||
const password = new PasswordRandomizer(randomizer);
|
const password = new PasswordRandomizer(randomizer, Date.now);
|
||||||
randomizer.pickWord.mockResolvedValueOnce("Foo");
|
randomizer.pickWord.mockResolvedValueOnce("Foo");
|
||||||
|
|
||||||
const result = await password.randomEffLongWords({
|
const result = await password.randomEffLongWords({
|
||||||
@@ -298,7 +298,7 @@ describe("PasswordRandomizer", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it("includes a random number on a random word", async () => {
|
it("includes a random number on a random word", async () => {
|
||||||
const password = new PasswordRandomizer(randomizer);
|
const password = new PasswordRandomizer(randomizer, Date.now);
|
||||||
randomizer.pickWord.mockResolvedValueOnce("foo");
|
randomizer.pickWord.mockResolvedValueOnce("foo");
|
||||||
randomizer.pickWord.mockResolvedValueOnce("foo1");
|
randomizer.pickWord.mockResolvedValueOnce("foo1");
|
||||||
|
|
||||||
@@ -324,7 +324,7 @@ describe("PasswordRandomizer", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it("includes a separator", async () => {
|
it("includes a separator", async () => {
|
||||||
const password = new PasswordRandomizer(randomizer);
|
const password = new PasswordRandomizer(randomizer, Date.now);
|
||||||
|
|
||||||
const result = await password.randomEffLongWords({
|
const result = await password.randomEffLongWords({
|
||||||
numberOfWords: 2,
|
numberOfWords: 2,
|
||||||
@@ -339,7 +339,7 @@ describe("PasswordRandomizer", () => {
|
|||||||
|
|
||||||
describe("generate", () => {
|
describe("generate", () => {
|
||||||
it("processes password generation options", async () => {
|
it("processes password generation options", async () => {
|
||||||
const password = new PasswordRandomizer(randomizer);
|
const password = new PasswordRandomizer(randomizer, Date.now);
|
||||||
|
|
||||||
const result = await password.generate(
|
const result = await password.generate(
|
||||||
{ algorithm: Algorithm.password },
|
{ algorithm: Algorithm.password },
|
||||||
@@ -352,7 +352,7 @@ describe("PasswordRandomizer", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it("processes passphrase generation options", async () => {
|
it("processes passphrase generation options", async () => {
|
||||||
const password = new PasswordRandomizer(randomizer);
|
const password = new PasswordRandomizer(randomizer, Date.now);
|
||||||
|
|
||||||
const result = await password.generate(
|
const result = await password.generate(
|
||||||
{ algorithm: Algorithm.passphrase },
|
{ algorithm: Algorithm.passphrase },
|
||||||
@@ -365,7 +365,7 @@ describe("PasswordRandomizer", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it("throws when it cannot recognize the options type", async () => {
|
it("throws when it cannot recognize the options type", async () => {
|
||||||
const password = new PasswordRandomizer(randomizer);
|
const password = new PasswordRandomizer(randomizer, Date.now);
|
||||||
|
|
||||||
const result = password.generate({ algorithm: Algorithm.username }, {});
|
const result = password.generate({ algorithm: Algorithm.username }, {});
|
||||||
|
|
||||||
|
|||||||
@@ -25,7 +25,10 @@ export class PasswordRandomizer
|
|||||||
/** Instantiates the password randomizer
|
/** Instantiates the password randomizer
|
||||||
* @param randomizer data source for random data
|
* @param randomizer data source for random data
|
||||||
*/
|
*/
|
||||||
constructor(private randomizer: Randomizer) {}
|
constructor(
|
||||||
|
private randomizer: Randomizer,
|
||||||
|
private currentTime: () => number,
|
||||||
|
) {}
|
||||||
|
|
||||||
/** create a password from ASCII codepoints
|
/** create a password from ASCII codepoints
|
||||||
* @param request refines the generated password
|
* @param request refines the generated password
|
||||||
@@ -88,7 +91,7 @@ export class PasswordRandomizer
|
|||||||
return new GeneratedCredential(
|
return new GeneratedCredential(
|
||||||
password,
|
password,
|
||||||
Type.password,
|
Type.password,
|
||||||
Date.now(),
|
this.currentTime(),
|
||||||
request.source,
|
request.source,
|
||||||
request.website,
|
request.website,
|
||||||
);
|
);
|
||||||
@@ -99,7 +102,7 @@ export class PasswordRandomizer
|
|||||||
return new GeneratedCredential(
|
return new GeneratedCredential(
|
||||||
passphrase,
|
passphrase,
|
||||||
Type.password,
|
Type.password,
|
||||||
Date.now(),
|
this.currentTime(),
|
||||||
request.source,
|
request.source,
|
||||||
request.website,
|
request.website,
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -8,12 +8,6 @@ export const Algorithm = Object.freeze({
|
|||||||
/** A password composed of random words from the EFF word list */
|
/** A password composed of random words from the EFF word list */
|
||||||
passphrase: "passphrase",
|
passphrase: "passphrase",
|
||||||
|
|
||||||
/** A password composed of random characters, retrieved from SDK */
|
|
||||||
sdkPassword: "sdkPassword",
|
|
||||||
|
|
||||||
/** A password composed of random words from the EFF word list, retrieved from SDK */
|
|
||||||
sdkPassphrase: "sdkPassphrase",
|
|
||||||
|
|
||||||
/** A username composed of words from the EFF word list */
|
/** A username composed of words from the EFF word list */
|
||||||
username: "username",
|
username: "username",
|
||||||
|
|
||||||
@@ -44,12 +38,7 @@ export const Profile = Object.freeze({
|
|||||||
/** Credential generation algorithms grouped by purpose. */
|
/** Credential generation algorithms grouped by purpose. */
|
||||||
export const AlgorithmsByType = deepFreeze({
|
export const AlgorithmsByType = deepFreeze({
|
||||||
/** Algorithms that produce passwords */
|
/** Algorithms that produce passwords */
|
||||||
[Type.password]: [
|
[Type.password]: [Algorithm.password, Algorithm.passphrase] as const,
|
||||||
Algorithm.password,
|
|
||||||
Algorithm.passphrase,
|
|
||||||
Algorithm.sdkPassword,
|
|
||||||
Algorithm.sdkPassphrase,
|
|
||||||
] as const,
|
|
||||||
|
|
||||||
/** Algorithms that produce usernames */
|
/** Algorithms that produce usernames */
|
||||||
[Type.username]: [Algorithm.username] as const,
|
[Type.username]: [Algorithm.username] as const,
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import { mock } from "jest-mock-extended";
|
|||||||
import { PolicyType } from "@bitwarden/common/admin-console/enums";
|
import { PolicyType } from "@bitwarden/common/admin-console/enums";
|
||||||
import { Policy } from "@bitwarden/common/admin-console/models/domain/policy";
|
import { Policy } from "@bitwarden/common/admin-console/models/domain/policy";
|
||||||
|
|
||||||
import { PasswordRandomizer } from "../../engine";
|
import { PasswordRandomizer, SdkPasswordRandomizer } from "../../engine";
|
||||||
import { PassphrasePolicyConstraints } from "../../policies";
|
import { PassphrasePolicyConstraints } from "../../policies";
|
||||||
import { GeneratorDependencyProvider } from "../../providers";
|
import { GeneratorDependencyProvider } from "../../providers";
|
||||||
import { PassphraseGenerationOptions } from "../../types";
|
import { PassphraseGenerationOptions } from "../../types";
|
||||||
@@ -17,8 +17,18 @@ const dependencyProvider = mock<GeneratorDependencyProvider>();
|
|||||||
|
|
||||||
describe("password - eff words generator metadata", () => {
|
describe("password - eff words generator metadata", () => {
|
||||||
describe("engine.create", () => {
|
describe("engine.create", () => {
|
||||||
it("returns an email randomizer", () => {
|
it("returns an sdk password randomizer", () => {
|
||||||
expect(effPassphrase.engine.create(dependencyProvider)).toBeInstanceOf(PasswordRandomizer);
|
expect(effPassphrase.engine.create(dependencyProvider)).toBeInstanceOf(SdkPasswordRandomizer);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("engine.create", () => {
|
||||||
|
const nonSdkDependencyProvider = mock<GeneratorDependencyProvider>();
|
||||||
|
nonSdkDependencyProvider.sdk = undefined;
|
||||||
|
it("returns a password randomizer", () => {
|
||||||
|
expect(effPassphrase.engine.create(nonSdkDependencyProvider)).toBeInstanceOf(
|
||||||
|
PasswordRandomizer,
|
||||||
|
);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import { GENERATOR_DISK } from "@bitwarden/common/platform/state";
|
|||||||
import { PublicClassifier } from "@bitwarden/common/tools/public-classifier";
|
import { PublicClassifier } from "@bitwarden/common/tools/public-classifier";
|
||||||
import { ObjectKey } from "@bitwarden/common/tools/state/object-key";
|
import { ObjectKey } from "@bitwarden/common/tools/state/object-key";
|
||||||
|
|
||||||
import { PasswordRandomizer } from "../../engine";
|
import { PasswordRandomizer, SdkPasswordRandomizer } from "../../engine";
|
||||||
import { passphraseLeastPrivilege, PassphrasePolicyConstraints } from "../../policies";
|
import { passphraseLeastPrivilege, PassphrasePolicyConstraints } from "../../policies";
|
||||||
import { GeneratorDependencyProvider } from "../../providers";
|
import { GeneratorDependencyProvider } from "../../providers";
|
||||||
import { CredentialGenerator, PassphraseGenerationOptions } from "../../types";
|
import { CredentialGenerator, PassphraseGenerationOptions } from "../../types";
|
||||||
@@ -30,7 +30,10 @@ const passphrase: GeneratorMetadata<PassphraseGenerationOptions> = {
|
|||||||
create(
|
create(
|
||||||
dependencies: GeneratorDependencyProvider,
|
dependencies: GeneratorDependencyProvider,
|
||||||
): CredentialGenerator<PassphraseGenerationOptions> {
|
): CredentialGenerator<PassphraseGenerationOptions> {
|
||||||
return new PasswordRandomizer(dependencies.randomizer);
|
if (dependencies.sdk == undefined) {
|
||||||
|
return new PasswordRandomizer(dependencies.randomizer, dependencies.now);
|
||||||
|
}
|
||||||
|
return new SdkPasswordRandomizer(dependencies.sdk, dependencies.now);
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
profiles: {
|
profiles: {
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import { mock } from "jest-mock-extended";
|
|||||||
import { PolicyType } from "@bitwarden/common/admin-console/enums";
|
import { PolicyType } from "@bitwarden/common/admin-console/enums";
|
||||||
import { Policy } from "@bitwarden/common/admin-console/models/domain/policy";
|
import { Policy } from "@bitwarden/common/admin-console/models/domain/policy";
|
||||||
|
|
||||||
import { PasswordRandomizer } from "../../engine";
|
import { PasswordRandomizer, SdkPasswordRandomizer } from "../../engine";
|
||||||
import { DynamicPasswordPolicyConstraints } from "../../policies";
|
import { DynamicPasswordPolicyConstraints } from "../../policies";
|
||||||
import { GeneratorDependencyProvider } from "../../providers";
|
import { GeneratorDependencyProvider } from "../../providers";
|
||||||
import { PasswordGenerationOptions } from "../../types";
|
import { PasswordGenerationOptions } from "../../types";
|
||||||
@@ -17,8 +17,16 @@ const dependencyProvider = mock<GeneratorDependencyProvider>();
|
|||||||
|
|
||||||
describe("password - characters generator metadata", () => {
|
describe("password - characters generator metadata", () => {
|
||||||
describe("engine.create", () => {
|
describe("engine.create", () => {
|
||||||
it("returns an email randomizer", () => {
|
it("returns an sdk password randomizer", () => {
|
||||||
expect(password.engine.create(dependencyProvider)).toBeInstanceOf(PasswordRandomizer);
|
expect(password.engine.create(dependencyProvider)).toBeInstanceOf(SdkPasswordRandomizer);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("engine.create", () => {
|
||||||
|
const nonSdkDependencyProvider = mock<GeneratorDependencyProvider>();
|
||||||
|
nonSdkDependencyProvider.sdk = undefined;
|
||||||
|
it("returns a password randomizer", () => {
|
||||||
|
expect(password.engine.create(nonSdkDependencyProvider)).toBeInstanceOf(PasswordRandomizer);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import { GENERATOR_DISK } from "@bitwarden/common/platform/state";
|
|||||||
import { PublicClassifier } from "@bitwarden/common/tools/public-classifier";
|
import { PublicClassifier } from "@bitwarden/common/tools/public-classifier";
|
||||||
import { deepFreeze } from "@bitwarden/common/tools/util";
|
import { deepFreeze } from "@bitwarden/common/tools/util";
|
||||||
|
|
||||||
import { PasswordRandomizer } from "../../engine";
|
import { PasswordRandomizer, SdkPasswordRandomizer } from "../../engine";
|
||||||
import { DynamicPasswordPolicyConstraints, passwordLeastPrivilege } from "../../policies";
|
import { DynamicPasswordPolicyConstraints, passwordLeastPrivilege } from "../../policies";
|
||||||
import { GeneratorDependencyProvider } from "../../providers";
|
import { GeneratorDependencyProvider } from "../../providers";
|
||||||
import { CredentialGenerator, PasswordGeneratorSettings } from "../../types";
|
import { CredentialGenerator, PasswordGeneratorSettings } from "../../types";
|
||||||
@@ -30,7 +30,10 @@ const password: GeneratorMetadata<PasswordGeneratorSettings> = deepFreeze({
|
|||||||
create(
|
create(
|
||||||
dependencies: GeneratorDependencyProvider,
|
dependencies: GeneratorDependencyProvider,
|
||||||
): CredentialGenerator<PasswordGeneratorSettings> {
|
): CredentialGenerator<PasswordGeneratorSettings> {
|
||||||
return new PasswordRandomizer(dependencies.randomizer);
|
if (dependencies.sdk == undefined) {
|
||||||
|
return new PasswordRandomizer(dependencies.randomizer, dependencies.now);
|
||||||
|
}
|
||||||
|
return new SdkPasswordRandomizer(dependencies.sdk, dependencies.now);
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
profiles: {
|
profiles: {
|
||||||
|
|||||||
@@ -1,107 +0,0 @@
|
|||||||
import { mock } from "jest-mock-extended";
|
|
||||||
|
|
||||||
import { PolicyType } from "@bitwarden/common/admin-console/enums";
|
|
||||||
import { Policy } from "@bitwarden/common/admin-console/models/domain/policy";
|
|
||||||
|
|
||||||
import { SdkPasswordRandomizer } from "../../engine";
|
|
||||||
import { PassphrasePolicyConstraints } from "../../policies";
|
|
||||||
import { GeneratorDependencyProvider } from "../../providers";
|
|
||||||
import { PassphraseGenerationOptions } from "../../types";
|
|
||||||
import { Profile } from "../data";
|
|
||||||
import { CoreProfileMetadata } from "../profile-metadata";
|
|
||||||
import { isCoreProfile } from "../util";
|
|
||||||
|
|
||||||
import sdkEffPassphrase from "./sdk-eff-word-list";
|
|
||||||
|
|
||||||
const dependencyProvider = mock<GeneratorDependencyProvider>();
|
|
||||||
|
|
||||||
describe("password - eff words generator metadata", () => {
|
|
||||||
describe("engine.create", () => {
|
|
||||||
it("returns an email randomizer", () => {
|
|
||||||
expect(sdkEffPassphrase.engine.create(dependencyProvider)).toBeInstanceOf(
|
|
||||||
SdkPasswordRandomizer,
|
|
||||||
);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe("profiles[account]", () => {
|
|
||||||
let accountProfile: CoreProfileMetadata<PassphraseGenerationOptions> | null = null;
|
|
||||||
beforeEach(() => {
|
|
||||||
const profile = sdkEffPassphrase.profiles[Profile.account];
|
|
||||||
if (isCoreProfile(profile!)) {
|
|
||||||
accountProfile = profile;
|
|
||||||
} else {
|
|
||||||
accountProfile = null;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
describe("storage.options.deserializer", () => {
|
|
||||||
it("returns its input", () => {
|
|
||||||
const value: PassphraseGenerationOptions = { ...accountProfile!.storage.initial };
|
|
||||||
|
|
||||||
const result = accountProfile!.storage.options.deserializer(value);
|
|
||||||
|
|
||||||
expect(result).toBe(value);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe("constraints.create", () => {
|
|
||||||
// these tests check that the wiring is correct by exercising the behavior
|
|
||||||
// of functionality encapsulated by `create`. These methods may fail if the
|
|
||||||
// enclosed behaviors change.
|
|
||||||
|
|
||||||
it("creates a passphrase policy constraints", () => {
|
|
||||||
const context = { defaultConstraints: accountProfile!.constraints.default };
|
|
||||||
|
|
||||||
const constraints = accountProfile!.constraints.create([], context);
|
|
||||||
|
|
||||||
expect(constraints).toBeInstanceOf(PassphrasePolicyConstraints);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("forwards the policy to the constraints", () => {
|
|
||||||
const context = { defaultConstraints: accountProfile!.constraints.default };
|
|
||||||
const policies = [
|
|
||||||
{
|
|
||||||
type: PolicyType.PasswordGenerator,
|
|
||||||
data: {
|
|
||||||
minNumberWords: 6,
|
|
||||||
capitalize: false,
|
|
||||||
includeNumber: false,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
] as Policy[];
|
|
||||||
|
|
||||||
const constraints = accountProfile!.constraints.create(policies, context);
|
|
||||||
|
|
||||||
expect(constraints.constraints.numWords?.min).toEqual(6);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("combines multiple policies in the constraints", () => {
|
|
||||||
const context = { defaultConstraints: accountProfile!.constraints.default };
|
|
||||||
const policies = [
|
|
||||||
{
|
|
||||||
type: PolicyType.PasswordGenerator,
|
|
||||||
data: {
|
|
||||||
minNumberWords: 6,
|
|
||||||
capitalize: false,
|
|
||||||
includeNumber: false,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
type: PolicyType.PasswordGenerator,
|
|
||||||
data: {
|
|
||||||
minNumberWords: 3,
|
|
||||||
capitalize: true,
|
|
||||||
includeNumber: false,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
] as Policy[];
|
|
||||||
|
|
||||||
const constraints = accountProfile!.constraints.create(policies, context);
|
|
||||||
|
|
||||||
expect(constraints.constraints.numWords?.min).toEqual(6);
|
|
||||||
expect(constraints.constraints.capitalize?.requiredValue).toEqual(true);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@@ -1,89 +0,0 @@
|
|||||||
import { PolicyType } from "@bitwarden/common/admin-console/enums";
|
|
||||||
import { GENERATOR_DISK } from "@bitwarden/common/platform/state";
|
|
||||||
import { PublicClassifier } from "@bitwarden/common/tools/public-classifier";
|
|
||||||
import { ObjectKey } from "@bitwarden/common/tools/state/object-key";
|
|
||||||
import { BitwardenClient } from "@bitwarden/sdk-internal";
|
|
||||||
|
|
||||||
import { SdkPasswordRandomizer } from "../../engine";
|
|
||||||
import { passphraseLeastPrivilege, PassphrasePolicyConstraints } from "../../policies";
|
|
||||||
import { GeneratorDependencyProvider } from "../../providers";
|
|
||||||
import { CredentialGenerator, PassphraseGenerationOptions } from "../../types";
|
|
||||||
import { Algorithm, Profile, Type } from "../data";
|
|
||||||
import { GeneratorMetadata } from "../generator-metadata";
|
|
||||||
|
|
||||||
const sdkPassphrase: GeneratorMetadata<PassphraseGenerationOptions> = {
|
|
||||||
id: Algorithm.sdkPassphrase,
|
|
||||||
type: Type.password,
|
|
||||||
weight: 130,
|
|
||||||
i18nKeys: {
|
|
||||||
name: "passphrase",
|
|
||||||
credentialType: "passphrase",
|
|
||||||
generateCredential: "generatePassphrase",
|
|
||||||
credentialGenerated: "passphraseGenerated",
|
|
||||||
copyCredential: "copyPassphrase",
|
|
||||||
useCredential: "useThisPassphrase",
|
|
||||||
},
|
|
||||||
capabilities: {
|
|
||||||
autogenerate: false,
|
|
||||||
fields: [],
|
|
||||||
},
|
|
||||||
engine: {
|
|
||||||
create(
|
|
||||||
dependencies: GeneratorDependencyProvider,
|
|
||||||
): CredentialGenerator<PassphraseGenerationOptions> {
|
|
||||||
return new SdkPasswordRandomizer(new BitwardenClient(null), Date.now); // @TODO hook up a real SDK client
|
|
||||||
},
|
|
||||||
},
|
|
||||||
profiles: {
|
|
||||||
[Profile.account]: {
|
|
||||||
type: "core",
|
|
||||||
storage: {
|
|
||||||
key: "passphraseGeneratorSettings",
|
|
||||||
target: "object",
|
|
||||||
format: "plain",
|
|
||||||
classifier: new PublicClassifier<PassphraseGenerationOptions>([
|
|
||||||
"numWords",
|
|
||||||
"wordSeparator",
|
|
||||||
"capitalize",
|
|
||||||
"includeNumber",
|
|
||||||
]),
|
|
||||||
state: GENERATOR_DISK,
|
|
||||||
initial: {
|
|
||||||
numWords: 6,
|
|
||||||
wordSeparator: "-",
|
|
||||||
capitalize: false,
|
|
||||||
includeNumber: false,
|
|
||||||
},
|
|
||||||
options: {
|
|
||||||
deserializer(value) {
|
|
||||||
return value;
|
|
||||||
},
|
|
||||||
clearOn: ["logout"],
|
|
||||||
},
|
|
||||||
} satisfies ObjectKey<PassphraseGenerationOptions>,
|
|
||||||
constraints: {
|
|
||||||
type: PolicyType.PasswordGenerator,
|
|
||||||
default: {
|
|
||||||
wordSeparator: { maxLength: 1 },
|
|
||||||
numWords: {
|
|
||||||
min: 3,
|
|
||||||
max: 20,
|
|
||||||
recommendation: 6,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
create(policies, context) {
|
|
||||||
const initial = {
|
|
||||||
minNumberWords: 0,
|
|
||||||
capitalize: false,
|
|
||||||
includeNumber: false,
|
|
||||||
};
|
|
||||||
const policy = policies.reduce(passphraseLeastPrivilege, initial);
|
|
||||||
const constraints = new PassphrasePolicyConstraints(policy, context.defaultConstraints);
|
|
||||||
return constraints;
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
export default sdkPassphrase;
|
|
||||||
@@ -1,108 +0,0 @@
|
|||||||
import { mock } from "jest-mock-extended";
|
|
||||||
|
|
||||||
import { PolicyType } from "@bitwarden/common/admin-console/enums";
|
|
||||||
import { Policy } from "@bitwarden/common/admin-console/models/domain/policy";
|
|
||||||
|
|
||||||
import { SdkPasswordRandomizer } from "../../engine";
|
|
||||||
import { DynamicPasswordPolicyConstraints } from "../../policies";
|
|
||||||
import { GeneratorDependencyProvider } from "../../providers";
|
|
||||||
import { PasswordGenerationOptions } from "../../types";
|
|
||||||
import { Profile } from "../data";
|
|
||||||
import { CoreProfileMetadata } from "../profile-metadata";
|
|
||||||
import { isCoreProfile } from "../util";
|
|
||||||
|
|
||||||
import sdkPassword from "./sdk-random-password";
|
|
||||||
|
|
||||||
const dependencyProvider = mock<GeneratorDependencyProvider>();
|
|
||||||
|
|
||||||
describe("password - characters generator metadata", () => {
|
|
||||||
describe("engine.create", () => {
|
|
||||||
it("returns an email randomizer", () => {
|
|
||||||
expect(sdkPassword.engine.create(dependencyProvider)).toBeInstanceOf(SdkPasswordRandomizer);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe("profiles[account]", () => {
|
|
||||||
let accountProfile: CoreProfileMetadata<PasswordGenerationOptions> = null!;
|
|
||||||
beforeEach(() => {
|
|
||||||
const profile = sdkPassword.profiles[Profile.account];
|
|
||||||
if (isCoreProfile(profile!)) {
|
|
||||||
accountProfile = profile;
|
|
||||||
} else {
|
|
||||||
throw new Error("this branch should never run");
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
describe("storage.options.deserializer", () => {
|
|
||||||
it("returns its input", () => {
|
|
||||||
const value: PasswordGenerationOptions = { ...accountProfile.storage.initial };
|
|
||||||
|
|
||||||
const result = accountProfile.storage.options.deserializer(value);
|
|
||||||
|
|
||||||
expect(result).toBe(value);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe("constraints.create", () => {
|
|
||||||
// these tests check that the wiring is correct by exercising the behavior
|
|
||||||
// of functionality encapsulated by `create`. These methods may fail if the
|
|
||||||
// enclosed behaviors change.
|
|
||||||
|
|
||||||
it("creates a passphrase policy constraints", () => {
|
|
||||||
const context = { defaultConstraints: accountProfile.constraints.default };
|
|
||||||
|
|
||||||
const constraints = accountProfile.constraints.create([], context);
|
|
||||||
|
|
||||||
expect(constraints).toBeInstanceOf(DynamicPasswordPolicyConstraints);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("forwards the policy to the constraints", () => {
|
|
||||||
const context = { defaultConstraints: accountProfile.constraints.default };
|
|
||||||
const policies = [
|
|
||||||
{
|
|
||||||
type: PolicyType.PasswordGenerator,
|
|
||||||
enabled: true,
|
|
||||||
data: {
|
|
||||||
minLength: 10,
|
|
||||||
capitalize: false,
|
|
||||||
useNumbers: false,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
] as Policy[];
|
|
||||||
|
|
||||||
const constraints = accountProfile.constraints.create(policies, context);
|
|
||||||
|
|
||||||
expect(constraints.constraints.length?.min).toEqual(10);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("combines multiple policies in the constraints", () => {
|
|
||||||
const context = { defaultConstraints: accountProfile.constraints.default };
|
|
||||||
const policies = [
|
|
||||||
{
|
|
||||||
type: PolicyType.PasswordGenerator,
|
|
||||||
enabled: true,
|
|
||||||
data: {
|
|
||||||
minLength: 14,
|
|
||||||
useSpecial: false,
|
|
||||||
useNumbers: false,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
type: PolicyType.PasswordGenerator,
|
|
||||||
enabled: true,
|
|
||||||
data: {
|
|
||||||
minLength: 10,
|
|
||||||
useSpecial: true,
|
|
||||||
includeNumber: false,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
] as Policy[];
|
|
||||||
|
|
||||||
const constraints = accountProfile.constraints.create(policies, context);
|
|
||||||
|
|
||||||
expect(constraints.constraints.length?.min).toEqual(14);
|
|
||||||
expect(constraints.constraints.special?.requiredValue).toEqual(true);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@@ -1,115 +0,0 @@
|
|||||||
import { PolicyType } from "@bitwarden/common/admin-console/enums";
|
|
||||||
import { GENERATOR_DISK } from "@bitwarden/common/platform/state";
|
|
||||||
import { PublicClassifier } from "@bitwarden/common/tools/public-classifier";
|
|
||||||
import { deepFreeze } from "@bitwarden/common/tools/util";
|
|
||||||
import { BitwardenClient } from "@bitwarden/sdk-internal";
|
|
||||||
|
|
||||||
import { SdkPasswordRandomizer } from "../../engine";
|
|
||||||
import { DynamicPasswordPolicyConstraints, passwordLeastPrivilege } from "../../policies";
|
|
||||||
import { GeneratorDependencyProvider } from "../../providers";
|
|
||||||
import { CredentialGenerator, PasswordGeneratorSettings } from "../../types";
|
|
||||||
import { Algorithm, Profile, Type } from "../data";
|
|
||||||
import { GeneratorMetadata } from "../generator-metadata";
|
|
||||||
|
|
||||||
const sdkPassword: GeneratorMetadata<PasswordGeneratorSettings> = deepFreeze({
|
|
||||||
id: Algorithm.sdkPassword,
|
|
||||||
type: Type.password,
|
|
||||||
weight: 120,
|
|
||||||
i18nKeys: {
|
|
||||||
name: "password",
|
|
||||||
generateCredential: "generatePassword",
|
|
||||||
credentialGenerated: "passwordGenerated",
|
|
||||||
credentialType: "password",
|
|
||||||
copyCredential: "copyPassword",
|
|
||||||
useCredential: "useThisPassword",
|
|
||||||
},
|
|
||||||
capabilities: {
|
|
||||||
autogenerate: true,
|
|
||||||
fields: [],
|
|
||||||
},
|
|
||||||
engine: {
|
|
||||||
create(
|
|
||||||
dependencies: GeneratorDependencyProvider,
|
|
||||||
): CredentialGenerator<PasswordGeneratorSettings> {
|
|
||||||
return new SdkPasswordRandomizer(new BitwardenClient(null), Date.now); // @TODO hook up a real SDK client
|
|
||||||
},
|
|
||||||
},
|
|
||||||
profiles: {
|
|
||||||
[Profile.account]: {
|
|
||||||
type: "core",
|
|
||||||
storage: {
|
|
||||||
key: "passwordGeneratorSettings",
|
|
||||||
target: "object",
|
|
||||||
format: "plain",
|
|
||||||
classifier: new PublicClassifier<PasswordGeneratorSettings>([
|
|
||||||
"length",
|
|
||||||
"ambiguous",
|
|
||||||
"uppercase",
|
|
||||||
"minUppercase",
|
|
||||||
"lowercase",
|
|
||||||
"minLowercase",
|
|
||||||
"number",
|
|
||||||
"minNumber",
|
|
||||||
"special",
|
|
||||||
"minSpecial",
|
|
||||||
]),
|
|
||||||
state: GENERATOR_DISK,
|
|
||||||
initial: {
|
|
||||||
length: 14,
|
|
||||||
ambiguous: true,
|
|
||||||
uppercase: true,
|
|
||||||
minUppercase: 1,
|
|
||||||
lowercase: true,
|
|
||||||
minLowercase: 1,
|
|
||||||
number: true,
|
|
||||||
minNumber: 1,
|
|
||||||
special: false,
|
|
||||||
minSpecial: 0,
|
|
||||||
},
|
|
||||||
options: {
|
|
||||||
deserializer(value) {
|
|
||||||
return value;
|
|
||||||
},
|
|
||||||
clearOn: ["logout"],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
constraints: {
|
|
||||||
type: PolicyType.PasswordGenerator,
|
|
||||||
default: {
|
|
||||||
length: {
|
|
||||||
min: 5,
|
|
||||||
max: 128,
|
|
||||||
recommendation: 14,
|
|
||||||
},
|
|
||||||
minNumber: {
|
|
||||||
min: 0,
|
|
||||||
max: 9,
|
|
||||||
},
|
|
||||||
minSpecial: {
|
|
||||||
min: 0,
|
|
||||||
max: 9,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
create(policies, context) {
|
|
||||||
const initial = {
|
|
||||||
minLength: 0,
|
|
||||||
useUppercase: false,
|
|
||||||
useLowercase: false,
|
|
||||||
useNumbers: false,
|
|
||||||
numberCount: 0,
|
|
||||||
useSpecial: false,
|
|
||||||
specialCount: 0,
|
|
||||||
};
|
|
||||||
const policy = policies.reduce(passwordLeastPrivilege, initial);
|
|
||||||
const constraints = new DynamicPasswordPolicyConstraints(
|
|
||||||
policy,
|
|
||||||
context.defaultConstraints,
|
|
||||||
);
|
|
||||||
return constraints;
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
export default sdkPassword;
|
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
||||||
import { RestClient } from "@bitwarden/common/tools/integration/rpc";
|
import { RestClient } from "@bitwarden/common/tools/integration/rpc";
|
||||||
|
import { BitwardenClient } from "@bitwarden/sdk-internal";
|
||||||
|
|
||||||
import { Randomizer } from "../abstractions";
|
import { Randomizer } from "../abstractions";
|
||||||
|
|
||||||
@@ -9,4 +10,6 @@ export type GeneratorDependencyProvider = {
|
|||||||
// FIXME: introduce `I18nKeyOrLiteral` into forwarder
|
// FIXME: introduce `I18nKeyOrLiteral` into forwarder
|
||||||
// structures and remove this dependency
|
// structures and remove this dependency
|
||||||
i18nService: I18nService;
|
i18nService: I18nService;
|
||||||
|
sdk?: BitwardenClient;
|
||||||
|
now: () => number;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import { PolicyService } from "@bitwarden/common/admin-console/abstractions/poli
|
|||||||
import { PolicyType } from "@bitwarden/common/admin-console/enums";
|
import { PolicyType } from "@bitwarden/common/admin-console/enums";
|
||||||
import { Policy } from "@bitwarden/common/admin-console/models/domain/policy";
|
import { Policy } from "@bitwarden/common/admin-console/models/domain/policy";
|
||||||
import { Account } from "@bitwarden/common/auth/abstractions/account.service";
|
import { Account } from "@bitwarden/common/auth/abstractions/account.service";
|
||||||
|
import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service";
|
||||||
import { LegacyEncryptorProvider } from "@bitwarden/common/tools/cryptography/legacy-encryptor-provider";
|
import { LegacyEncryptorProvider } from "@bitwarden/common/tools/cryptography/legacy-encryptor-provider";
|
||||||
import { UserEncryptor } from "@bitwarden/common/tools/cryptography/user-encryptor.abstraction";
|
import { UserEncryptor } from "@bitwarden/common/tools/cryptography/user-encryptor.abstraction";
|
||||||
import {
|
import {
|
||||||
@@ -22,6 +23,7 @@ import { UserStateSubject } from "@bitwarden/common/tools/state/user-state-subje
|
|||||||
import { UserStateSubjectDependencyProvider } from "@bitwarden/common/tools/state/user-state-subject-dependency-provider";
|
import { UserStateSubjectDependencyProvider } from "@bitwarden/common/tools/state/user-state-subject-dependency-provider";
|
||||||
import { deepFreeze } from "@bitwarden/common/tools/util";
|
import { deepFreeze } from "@bitwarden/common/tools/util";
|
||||||
import { UserId } from "@bitwarden/common/types/guid";
|
import { UserId } from "@bitwarden/common/types/guid";
|
||||||
|
import { BitwardenClient } from "@bitwarden/sdk-internal";
|
||||||
|
|
||||||
import { FakeAccountService, FakeStateProvider } from "../../../../../common/spec";
|
import { FakeAccountService, FakeStateProvider } from "../../../../../common/spec";
|
||||||
import { Algorithm, AlgorithmsByType, CredentialAlgorithm, Type, Types } from "../metadata";
|
import { Algorithm, AlgorithmsByType, CredentialAlgorithm, Type, Types } from "../metadata";
|
||||||
@@ -89,6 +91,10 @@ const SomePolicyService = mock<PolicyService>();
|
|||||||
|
|
||||||
const SomeExtensionService = mock<ExtensionService>();
|
const SomeExtensionService = mock<ExtensionService>();
|
||||||
|
|
||||||
|
const SomeConfigService = mock<ConfigService>;
|
||||||
|
|
||||||
|
const SomeSdkService = mock<BitwardenClient>;
|
||||||
|
|
||||||
const ApplicationProvider = {
|
const ApplicationProvider = {
|
||||||
/** Policy configured by the administrative console */
|
/** Policy configured by the administrative console */
|
||||||
policy: SomePolicyService,
|
policy: SomePolicyService,
|
||||||
@@ -98,7 +104,13 @@ const ApplicationProvider = {
|
|||||||
|
|
||||||
/** Event monitoring and diagnostic interfaces */
|
/** Event monitoring and diagnostic interfaces */
|
||||||
log: disabledSemanticLoggerProvider,
|
log: disabledSemanticLoggerProvider,
|
||||||
} as SystemServiceProvider;
|
|
||||||
|
/** Feature flag retrieval */
|
||||||
|
configService: SomeConfigService,
|
||||||
|
|
||||||
|
/** SDK access for password generation */
|
||||||
|
sdk: SomeSdkService,
|
||||||
|
} as unknown as SystemServiceProvider;
|
||||||
|
|
||||||
describe("GeneratorMetadataProvider", () => {
|
describe("GeneratorMetadataProvider", () => {
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ export function legacyPasswordGenerationServiceFactory(
|
|||||||
stateProvider: StateProvider,
|
stateProvider: StateProvider,
|
||||||
): PasswordGenerationServiceAbstraction {
|
): PasswordGenerationServiceAbstraction {
|
||||||
const randomizer = new KeyServiceRandomizer(keyService);
|
const randomizer = new KeyServiceRandomizer(keyService);
|
||||||
const passwordRandomizer = new PasswordRandomizer(randomizer);
|
const passwordRandomizer = new PasswordRandomizer(randomizer, Date.now);
|
||||||
|
|
||||||
const passwords = new DefaultGeneratorService(
|
const passwords = new DefaultGeneratorService(
|
||||||
new PasswordGeneratorStrategy(passwordRandomizer, stateProvider),
|
new PasswordGeneratorStrategy(passwordRandomizer, stateProvider),
|
||||||
|
|||||||
Reference in New Issue
Block a user