1
0
mirror of https://github.com/bitwarden/browser synced 2025-12-18 17:23:37 +00:00

[EC-598] feat: allow user to pick which credential to use

This commit is contained in:
Andreas Coroiu
2023-01-05 15:07:07 +01:00
parent f0b8d32ee6
commit 132c3fe04d
7 changed files with 101 additions and 81 deletions

View File

@@ -3,7 +3,6 @@ export interface NewCredentialParams {
}
export abstract class Fido2UserInterfaceService {
verifyUser: () => Promise<boolean>;
verifyPresence: () => Promise<boolean>;
pickCredential: (cipherIds: string[]) => Promise<string>;
confirmNewCredential: (params: NewCredentialParams) => Promise<boolean>;
}

View File

@@ -120,21 +120,30 @@ export class Fido2Service implements Fido2ServiceAbstraction {
if (params.allowedCredentialIds && params.allowedCredentialIds.length > 0) {
// We're looking for regular non-resident keys
credential = await this.getCredential(params.allowedCredentialIds);
if (credential === undefined) {
throw new NoCredentialFoundError();
}
if (credential.origin !== params.origin) {
throw new OriginMismatchError();
}
await this.fido2UserInterfaceService.pickCredential([credential.credentialId.encoded]);
} else {
// We're looking for a resident key
credential = await this.getCredentialByRp(params.rpId);
}
const credentials = await this.getCredentialsByRp(params.rpId);
if (credential === undefined) {
throw new NoCredentialFoundError();
}
if (credentials.length === 0) {
throw new NoCredentialFoundError();
}
if (credential.origin !== params.origin) {
throw new OriginMismatchError();
const pickedId = await this.fido2UserInterfaceService.pickCredential(
credentials.map((c) => c.credentialId.encoded)
);
credential = credentials.find((c) => c.credentialId.encoded === pickedId);
}
const presence = await this.fido2UserInterfaceService.verifyPresence();
const encoder = new TextEncoder();
const clientData = encoder.encode(
JSON.stringify({
@@ -147,7 +156,7 @@ export class Fido2Service implements Fido2ServiceAbstraction {
const authData = await generateAuthData({
credentialId: credential.credentialId,
rpId: params.rpId,
userPresence: presence,
userPresence: true,
userVerification: true, // TODO: Change to false!
});
@@ -171,7 +180,7 @@ export class Fido2Service implements Fido2ServiceAbstraction {
for (const allowedCredential of allowedCredentialIds) {
cipher = await this.cipherService.get(allowedCredential);
if (cipher.deletedDate != undefined) {
if (cipher?.deletedDate != undefined) {
cipher = undefined;
}
@@ -209,17 +218,13 @@ export class Fido2Service implements Fido2ServiceAbstraction {
return new CredentialId(cipher.id);
}
private async getCredentialByRp(rpId: string): Promise<BitCredential | undefined> {
private async getCredentialsByRp(rpId: string): Promise<BitCredential[]> {
const allCipherViews = await this.cipherService.getAllDecrypted();
const cipherView = allCipherViews.find(
const cipherViews = allCipherViews.filter(
(cv) => !cv.isDeleted && cv.type === CipherType.Fido2Key && cv.fido2Key?.rpId === rpId
);
if (cipherView == undefined) {
return undefined;
}
return await mapCipherViewToBitCredential(cipherView);
return await Promise.all(cipherViews.map((view) => mapCipherViewToBitCredential(view)));
}
}

View File

@@ -1,12 +1,9 @@
import { Fido2UserInterfaceService as Fido2UserInterfaceServiceAbstraction } from "../../abstractions/fido2/fido2-user-interface.service.abstraction";
import { RequestAbortedError } from "../../abstractions/fido2/fido2.service.abstraction";
export class Fido2UserInterfaceService implements Fido2UserInterfaceServiceAbstraction {
async verifyUser(): Promise<boolean> {
return false;
}
async verifyPresence(): Promise<boolean> {
return false;
pickCredential(cipherIds: string[]): Promise<string> {
throw new RequestAbortedError();
}
async confirmNewCredential(): Promise<boolean> {