mirror of
https://github.com/bitwarden/browser.git
synced 2025-03-02 03:41:09 +01:00
[PM-5973] add catchall generation strategy (#7898)
This commit is contained in:
parent
b37ba71712
commit
eafe3dec67
@ -1,6 +1,7 @@
|
||||
import {
|
||||
ENCRYPTED_HISTORY,
|
||||
EFF_USERNAME_SETTINGS,
|
||||
CATCHALL_SETTINGS,
|
||||
SUBADDRESS_SETTINGS,
|
||||
PASSPHRASE_SETTINGS,
|
||||
PASSWORD_SETTINGS,
|
||||
@ -23,7 +24,7 @@ describe("Key definitions", () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe("BASIC_LATIN_SETTINGS", () => {
|
||||
describe("EFF_USERNAME_SETTINGS", () => {
|
||||
it("should pass through deserialization", () => {
|
||||
const value = {};
|
||||
const result = EFF_USERNAME_SETTINGS.deserializer(value);
|
||||
@ -31,6 +32,14 @@ describe("Key definitions", () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe("CATCHALL_SETTINGS", () => {
|
||||
it("should pass through deserialization", () => {
|
||||
const value = {};
|
||||
const result = CATCHALL_SETTINGS.deserializer(value);
|
||||
expect(result).toBe(value);
|
||||
});
|
||||
});
|
||||
|
||||
describe("SUBADDRESS_SETTINGS", () => {
|
||||
it("should pass through deserialization", () => {
|
||||
const value = {};
|
||||
|
@ -3,6 +3,7 @@ import { GENERATOR_DISK, KeyDefinition } from "../../platform/state";
|
||||
import { PassphraseGenerationOptions } from "./passphrase/passphrase-generation-options";
|
||||
import { GeneratedPasswordHistory } from "./password/generated-password-history";
|
||||
import { PasswordGenerationOptions } from "./password/password-generation-options";
|
||||
import { CatchallGenerationOptions } from "./username/catchall-generator-options";
|
||||
import { EffUsernameGenerationOptions } from "./username/eff-username-generator-options";
|
||||
import { SubaddressGenerationOptions } from "./username/subaddress-generator-options";
|
||||
|
||||
@ -33,6 +34,15 @@ export const EFF_USERNAME_SETTINGS = new KeyDefinition<EffUsernameGenerationOpti
|
||||
},
|
||||
);
|
||||
|
||||
/** catchall email generation options */
|
||||
export const CATCHALL_SETTINGS = new KeyDefinition<CatchallGenerationOptions>(
|
||||
GENERATOR_DISK,
|
||||
"catchallGeneratorSettings",
|
||||
{
|
||||
deserializer: (value) => value,
|
||||
},
|
||||
);
|
||||
|
||||
/** email subaddress generation options */
|
||||
export const SUBADDRESS_SETTINGS = new KeyDefinition<SubaddressGenerationOptions>(
|
||||
GENERATOR_DISK,
|
||||
|
@ -0,0 +1,10 @@
|
||||
/** Settings supported when generating an email subaddress */
|
||||
export type CatchallGenerationOptions = {
|
||||
type?: "random" | "website-name";
|
||||
domain?: string;
|
||||
};
|
||||
|
||||
/** The default options for email subaddress generation. */
|
||||
export const DefaultCatchallOptions: Partial<CatchallGenerationOptions> = Object.freeze({
|
||||
type: "random",
|
||||
});
|
@ -0,0 +1,83 @@
|
||||
import { mock } from "jest-mock-extended";
|
||||
|
||||
import { PolicyType } from "../../../admin-console/enums";
|
||||
// FIXME: use index.ts imports once policy abstractions and models
|
||||
// implement ADR-0002
|
||||
import { Policy } from "../../../admin-console/models/domain/policy";
|
||||
import { DefaultPolicyEvaluator } from "../default-policy-evaluator";
|
||||
import { CATCHALL_SETTINGS } from "../key-definitions";
|
||||
|
||||
import { CatchallGeneratorStrategy, UsernameGenerationServiceAbstraction } from ".";
|
||||
|
||||
describe("Email subaddress list generation strategy", () => {
|
||||
describe("evaluator()", () => {
|
||||
it("should throw if the policy type is incorrect", () => {
|
||||
const strategy = new CatchallGeneratorStrategy(null);
|
||||
const policy = mock<Policy>({
|
||||
type: PolicyType.DisableSend,
|
||||
});
|
||||
|
||||
expect(() => strategy.evaluator(policy)).toThrow(new RegExp("Mismatched policy type\\. .+"));
|
||||
});
|
||||
|
||||
it("should map to the policy evaluator", () => {
|
||||
const strategy = new CatchallGeneratorStrategy(null);
|
||||
const policy = mock<Policy>({
|
||||
type: PolicyType.PasswordGenerator,
|
||||
data: {
|
||||
minLength: 10,
|
||||
},
|
||||
});
|
||||
|
||||
const evaluator = strategy.evaluator(policy);
|
||||
|
||||
expect(evaluator).toBeInstanceOf(DefaultPolicyEvaluator);
|
||||
expect(evaluator.policy).toMatchObject({});
|
||||
});
|
||||
});
|
||||
|
||||
describe("disk", () => {
|
||||
it("should use password settings key", () => {
|
||||
const legacy = mock<UsernameGenerationServiceAbstraction>();
|
||||
const strategy = new CatchallGeneratorStrategy(legacy);
|
||||
|
||||
expect(strategy.disk).toBe(CATCHALL_SETTINGS);
|
||||
});
|
||||
});
|
||||
|
||||
describe("cache_ms", () => {
|
||||
it("should be a positive non-zero number", () => {
|
||||
const legacy = mock<UsernameGenerationServiceAbstraction>();
|
||||
const strategy = new CatchallGeneratorStrategy(legacy);
|
||||
|
||||
expect(strategy.cache_ms).toBeGreaterThan(0);
|
||||
});
|
||||
});
|
||||
|
||||
describe("policy", () => {
|
||||
it("should use password generator policy", () => {
|
||||
const legacy = mock<UsernameGenerationServiceAbstraction>();
|
||||
const strategy = new CatchallGeneratorStrategy(legacy);
|
||||
|
||||
expect(strategy.policy).toBe(PolicyType.PasswordGenerator);
|
||||
});
|
||||
});
|
||||
|
||||
describe("generate()", () => {
|
||||
it("should call the legacy service with the given options", async () => {
|
||||
const legacy = mock<UsernameGenerationServiceAbstraction>();
|
||||
const strategy = new CatchallGeneratorStrategy(legacy);
|
||||
const options = {
|
||||
type: "website-name" as const,
|
||||
domain: "example.com",
|
||||
};
|
||||
|
||||
await strategy.generate(options);
|
||||
|
||||
expect(legacy.generateCatchall).toHaveBeenCalledWith({
|
||||
catchallType: "website-name" as const,
|
||||
catchallDomain: "example.com",
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
@ -0,0 +1,56 @@
|
||||
import { PolicyType } from "../../../admin-console/enums";
|
||||
import { Policy } from "../../../admin-console/models/domain/policy";
|
||||
import { GeneratorStrategy } from "../abstractions";
|
||||
import { DefaultPolicyEvaluator } from "../default-policy-evaluator";
|
||||
import { CATCHALL_SETTINGS } from "../key-definitions";
|
||||
import { NoPolicy } from "../no-policy";
|
||||
|
||||
import { CatchallGenerationOptions } from "./catchall-generator-options";
|
||||
import { UsernameGenerationServiceAbstraction } from "./username-generation.service.abstraction";
|
||||
|
||||
const ONE_MINUTE = 60 * 1000;
|
||||
|
||||
/** Strategy for creating usernames using a catchall email address */
|
||||
export class CatchallGeneratorStrategy
|
||||
implements GeneratorStrategy<CatchallGenerationOptions, NoPolicy>
|
||||
{
|
||||
/** Instantiates the generation strategy
|
||||
* @param usernameService generates a catchall address for a domain
|
||||
*/
|
||||
constructor(private usernameService: UsernameGenerationServiceAbstraction) {}
|
||||
|
||||
/** {@link GeneratorStrategy.disk} */
|
||||
get disk() {
|
||||
return CATCHALL_SETTINGS;
|
||||
}
|
||||
|
||||
/** {@link GeneratorStrategy.policy} */
|
||||
get policy() {
|
||||
// Uses password generator since there aren't policies
|
||||
// specific to usernames.
|
||||
return PolicyType.PasswordGenerator;
|
||||
}
|
||||
|
||||
/** {@link GeneratorStrategy.cache_ms} */
|
||||
get cache_ms() {
|
||||
return ONE_MINUTE;
|
||||
}
|
||||
|
||||
/** {@link GeneratorStrategy.evaluator} */
|
||||
evaluator(policy: Policy) {
|
||||
if (policy.type !== this.policy) {
|
||||
const details = `Expected: ${this.policy}. Received: ${policy.type}`;
|
||||
throw Error("Mismatched policy type. " + details);
|
||||
}
|
||||
|
||||
return new DefaultPolicyEvaluator<CatchallGenerationOptions>();
|
||||
}
|
||||
|
||||
/** {@link GeneratorStrategy.generate} */
|
||||
generate(options: CatchallGenerationOptions) {
|
||||
return this.usernameService.generateCatchall({
|
||||
catchallDomain: options.domain,
|
||||
catchallType: options.type,
|
||||
});
|
||||
}
|
||||
}
|
@ -1,4 +1,5 @@
|
||||
export { EffUsernameGeneratorStrategy } from "./eff-username-generator-strategy";
|
||||
export { CatchallGeneratorStrategy } from "./catchall-generator-strategy";
|
||||
export { SubaddressGeneratorStrategy } from "./subaddress-generator-strategy";
|
||||
export { UsernameGeneratorOptions } from "./username-generation-options";
|
||||
export { UsernameGenerationServiceAbstraction } from "./username-generation.service.abstraction";
|
||||
|
Loading…
Reference in New Issue
Block a user