mirror of
https://github.com/bitwarden/browser
synced 2025-12-15 15:53:27 +00:00
[PM-1500] Add feature flag to enable passkeys (#5406)
* Added launch darkly feature flag to passkeys implementation * fixed linter * Updated fido2 client service test to accomodate feature flag * Updated fido2client service to include unit test for feature flag * Renamed enable pass keys to fido2 vault credentials, added unit test when feature flag is not enabled * fixed failing Login domain test case
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
export enum FeatureFlag {
|
||||
DisplayEuEnvironmentFlag = "display-eu-environment",
|
||||
DisplayLowKdfIterationWarningFlag = "display-kdf-iteration-warning",
|
||||
Fido2VaultCredentials = "fido2-vault-credentials",
|
||||
TrustedDeviceEncryption = "trusted-device-encryption",
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { mock, MockProxy } from "jest-mock-extended";
|
||||
|
||||
import { ConfigServiceAbstraction } from "../../abstractions/config/config.service.abstraction";
|
||||
import { Utils } from "../../misc/utils";
|
||||
import {
|
||||
Fido2AutenticatorError,
|
||||
@@ -10,6 +11,7 @@ import {
|
||||
import {
|
||||
AssertCredentialParams,
|
||||
CreateCredentialParams,
|
||||
FallbackRequestedError,
|
||||
} from "../abstractions/fido2-client.service.abstraction";
|
||||
import { Fido2Utils } from "../abstractions/fido2-utils";
|
||||
|
||||
@@ -20,11 +22,14 @@ const RpId = "bitwarden.com";
|
||||
|
||||
describe("FidoAuthenticatorService", () => {
|
||||
let authenticator!: MockProxy<Fido2AuthenticatorService>;
|
||||
let configService!: MockProxy<ConfigServiceAbstraction>;
|
||||
let client!: Fido2ClientService;
|
||||
|
||||
beforeEach(async () => {
|
||||
authenticator = mock<Fido2AuthenticatorService>();
|
||||
client = new Fido2ClientService(authenticator);
|
||||
configService = mock<ConfigServiceAbstraction>();
|
||||
client = new Fido2ClientService(authenticator, configService);
|
||||
configService.getFeatureFlagBool.mockResolvedValue(true);
|
||||
});
|
||||
|
||||
describe("createCredential", () => {
|
||||
@@ -188,6 +193,16 @@ describe("FidoAuthenticatorService", () => {
|
||||
await rejects.toMatchObject({ name: "NotAllowedError" });
|
||||
await rejects.toBeInstanceOf(DOMException);
|
||||
});
|
||||
|
||||
it("should throw FallbackRequestedError if feature flag is not enabled", async () => {
|
||||
const params = createParams();
|
||||
configService.getFeatureFlagBool.mockResolvedValue(false);
|
||||
|
||||
const result = async () => await client.createCredential(params);
|
||||
|
||||
const rejects = expect(result).rejects;
|
||||
await rejects.toThrow(FallbackRequestedError);
|
||||
});
|
||||
});
|
||||
|
||||
function createParams(params: Partial<CreateCredentialParams> = {}): CreateCredentialParams {
|
||||
@@ -315,6 +330,16 @@ describe("FidoAuthenticatorService", () => {
|
||||
await rejects.toMatchObject({ name: "NotAllowedError" });
|
||||
await rejects.toBeInstanceOf(DOMException);
|
||||
});
|
||||
|
||||
it("should throw FallbackRequestedError if feature flag is not enabled", async () => {
|
||||
const params = createParams();
|
||||
configService.getFeatureFlagBool.mockResolvedValue(false);
|
||||
|
||||
const result = async () => await client.assertCredential(params);
|
||||
|
||||
const rejects = expect(result).rejects;
|
||||
await rejects.toThrow(FallbackRequestedError);
|
||||
});
|
||||
});
|
||||
|
||||
describe("assert non-discoverable credential", () => {
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
import { parse } from "tldts";
|
||||
|
||||
import { ConfigServiceAbstraction } from "../../abstractions/config/config.service.abstraction";
|
||||
import { LogService } from "../../abstractions/log.service";
|
||||
import { FeatureFlag } from "../../enums/feature-flag.enum";
|
||||
import { Utils } from "../../misc/utils";
|
||||
import {
|
||||
Fido2AutenticatorError,
|
||||
@@ -26,12 +28,25 @@ import { Fido2Utils } from "../abstractions/fido2-utils";
|
||||
import { isValidRpId } from "./domain-utils";
|
||||
|
||||
export class Fido2ClientService implements Fido2ClientServiceAbstraction {
|
||||
constructor(private authenticator: Fido2AuthenticatorService, private logService?: LogService) {}
|
||||
constructor(
|
||||
private authenticator: Fido2AuthenticatorService,
|
||||
private configService: ConfigServiceAbstraction,
|
||||
private logService?: LogService
|
||||
) {}
|
||||
|
||||
async createCredential(
|
||||
params: CreateCredentialParams,
|
||||
abortController = new AbortController()
|
||||
): Promise<CreateCredentialResult> {
|
||||
const enableFido2VaultCredentials = await this.configService.getFeatureFlagBool(
|
||||
FeatureFlag.Fido2VaultCredentials
|
||||
);
|
||||
|
||||
if (!enableFido2VaultCredentials) {
|
||||
this.logService?.warning(`[Fido2Client] Fido2VaultCredential is not enabled`);
|
||||
throw new FallbackRequestedError();
|
||||
}
|
||||
|
||||
if (!params.sameOriginWithAncestors) {
|
||||
this.logService?.warning(
|
||||
`[Fido2Client] Invalid 'sameOriginWithAncestors' value: ${params.sameOriginWithAncestors}`
|
||||
@@ -176,6 +191,15 @@ export class Fido2ClientService implements Fido2ClientServiceAbstraction {
|
||||
params: AssertCredentialParams,
|
||||
abortController = new AbortController()
|
||||
): Promise<AssertCredentialResult> {
|
||||
const enableFido2VaultCredentials = await this.configService.getFeatureFlagBool(
|
||||
FeatureFlag.Fido2VaultCredentials
|
||||
);
|
||||
|
||||
if (!enableFido2VaultCredentials) {
|
||||
this.logService?.warning(`[Fido2Client] Fido2VaultCredential is not enabled`);
|
||||
throw new FallbackRequestedError();
|
||||
}
|
||||
|
||||
const { domain: effectiveDomain } = parse(params.origin, { allowPrivateDomains: true });
|
||||
if (effectiveDomain == undefined) {
|
||||
this.logService?.warning(`[Fido2Client] Invalid origin: ${params.origin}`);
|
||||
|
||||
@@ -112,6 +112,19 @@ describe("Login DTO", () => {
|
||||
password: "myPassword",
|
||||
passwordRevisionDate: passwordRevisionDate.toISOString(),
|
||||
totp: "myTotp",
|
||||
fido2Key: {
|
||||
nonDiscoverableId: "keyId",
|
||||
keyType: "keyType",
|
||||
keyAlgorithm: "keyAlgorithm",
|
||||
keyCurve: "keyCurve",
|
||||
keyValue: "keyValue",
|
||||
rpId: "rpId",
|
||||
userHandle: "userHandle",
|
||||
counter: "counter",
|
||||
rpName: "rpName",
|
||||
userName: "userName",
|
||||
origin: "origin",
|
||||
},
|
||||
});
|
||||
|
||||
expect(actual).toEqual({
|
||||
@@ -120,6 +133,19 @@ describe("Login DTO", () => {
|
||||
password: "myPassword_fromJSON",
|
||||
passwordRevisionDate: passwordRevisionDate,
|
||||
totp: "myTotp_fromJSON",
|
||||
fido2Key: {
|
||||
nonDiscoverableId: "keyId_fromJSON",
|
||||
keyType: "keyType_fromJSON",
|
||||
keyAlgorithm: "keyAlgorithm_fromJSON",
|
||||
keyCurve: "keyCurve_fromJSON",
|
||||
keyValue: "keyValue_fromJSON",
|
||||
rpId: "rpId_fromJSON",
|
||||
userHandle: "userHandle_fromJSON",
|
||||
counter: "counter_fromJSON",
|
||||
rpName: "rpName_fromJSON",
|
||||
userName: "userName_fromJSON",
|
||||
origin: "origin_fromJSON",
|
||||
},
|
||||
});
|
||||
expect(actual).toBeInstanceOf(Login);
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user