1
0
mirror of https://github.com/bitwarden/browser.git synced 2025-01-31 22:51:28 +01:00

[EC-598] feat: start working on new Fido2ClientService

This commit is contained in:
Andreas Coroiu 2023-03-30 13:24:07 +02:00
parent e7454501ea
commit f172625f26
No known key found for this signature in database
GPG Key ID: E70B5FFC81DFEC1A
3 changed files with 174 additions and 0 deletions

View File

@ -0,0 +1,87 @@
export type UserVerification = "discouraged" | "preferred" | "required";
export abstract class Fido2ClientService {
createCredential: (
params: CreateCredentialParams,
abortController?: AbortController
) => Promise<CreateCredentialResult>;
assertCredential: (
params: AssertCredentialParams,
abortController?: AbortController
) => Promise<AssertCredentialResult>;
}
export interface CreateCredentialParams {
origin: string;
sameOriginWithAncestors: boolean;
attestation?: "direct" | "enterprise" | "indirect" | "none";
authenticatorSelection?: {
// authenticatorAttachment?: AuthenticatorAttachment; // not used
requireResidentKey?: boolean;
residentKey?: "discouraged" | "preferred" | "required";
userVerification?: UserVerification;
};
challenge: string; // b64 encoded
excludeCredentials?: {
id: string; // b64 encoded
transports?: ("ble" | "internal" | "nfc" | "usb")[];
// type: "public-key"; // not used
}[];
extensions?: {
appid?: string;
appidExclude?: string;
credProps?: boolean;
uvm?: boolean;
};
pubKeyCredParams: {
alg: number;
// type: "public-key"; // not used
}[];
rp: {
id?: string;
name: string;
};
user: {
id: string; // b64 encoded
displayName: string;
};
timeout?: number;
}
export interface CreateCredentialResult {
credentialId: string;
clientDataJSON: string;
attestationObject: string;
authData: string;
publicKeyAlgorithm: number;
transports: string[];
}
export interface AssertCredentialParams {
allowedCredentialIds: string[];
rpId: string;
origin: string;
challenge: string;
userVerification?: UserVerification;
timeout: number;
}
export interface AssertCredentialResult {
credentialId: string;
clientDataJSON: string;
authenticatorData: string;
signature: string;
userHandle: string;
}
export class Fido2Error extends Error {
constructor(message: string, readonly fallbackRequested = false) {
super(message);
}
}
export class RequestAbortedError extends Fido2Error {
constructor(fallbackRequested = false) {
super("Fido2 request was aborted", fallbackRequested);
}
}

View File

@ -0,0 +1,57 @@
import { mock, MockProxy } from "jest-mock-extended";
import { CreateCredentialParams } from "../abstractions/fido2-client.service.abstraction";
import { Fido2AuthenticatorService } from "./fido2-authenticator.service";
import { Fido2ClientService } from "./fido2-client.service";
const RpId = "bitwarden.com";
describe("FidoAuthenticatorService", () => {
let authenticator!: MockProxy<Fido2AuthenticatorService>;
let client!: Fido2ClientService;
beforeEach(async () => {
authenticator = mock<Fido2AuthenticatorService>();
client = new Fido2ClientService(authenticator);
});
describe("createCredential", () => {
describe("invalid input parameters", () => {
/** Spec: If sameOriginWithAncestors is false, return a "NotAllowedError" DOMException. */
it("throw error if sameOriginWithAncestors is false", async () => {
const params = createParams({ sameOriginWithAncestors: false });
const result = async () => await client.createCredential(params);
await expect(result).rejects.toThrowError(new DOMException(undefined, "NotAllowedError"));
});
});
function createParams(params: Partial<CreateCredentialParams> = {}): CreateCredentialParams {
return {
origin: params.origin ?? "bitwarden.com",
sameOriginWithAncestors: params.sameOriginWithAncestors ?? true,
attestation: params.attestation,
authenticatorSelection: params.authenticatorSelection,
challenge: params.challenge ?? "MzItYnl0ZXMtYmFzZTY0LWVuY29kZS1jaGFsbGVuZ2U",
excludeCredentials: params.excludeCredentials,
extensions: params.extensions,
pubKeyCredParams: params.pubKeyCredParams ?? [
{
alg: -7,
},
],
rp: params.rp ?? {
id: RpId,
name: "Bitwarden",
},
user: params.user ?? {
id: "YmFzZTY0LWVuY29kZWQtdXNlci1pZA",
displayName: "User Name",
},
timeout: params.timeout,
};
}
});
});

View File

@ -0,0 +1,30 @@
import { Fido2AuthenticatorService } from "../abstractions/fido2-authenticator.service.abstraction";
import {
AssertCredentialParams,
AssertCredentialResult,
CreateCredentialParams,
CreateCredentialResult,
Fido2ClientService as Fido2ClientServiceAbstraction,
} from "../abstractions/fido2-client.service.abstraction";
export class Fido2ClientService implements Fido2ClientServiceAbstraction {
constructor(private authenticator: Fido2AuthenticatorService) {}
createCredential(
params: CreateCredentialParams,
abortController?: AbortController
): Promise<CreateCredentialResult> {
if (!params.sameOriginWithAncestors) {
throw new DOMException(undefined, "NotAllowedError");
}
throw new Error("Not implemented");
}
assertCredential(
params: AssertCredentialParams,
abortController?: AbortController
): Promise<AssertCredentialResult> {
throw new Error("Not implemented");
}
}