diff --git a/apps/browser/src/popup/app.module.ts b/apps/browser/src/popup/app.module.ts
index 54443365d1b..e5ef2e7cade 100644
--- a/apps/browser/src/popup/app.module.ts
+++ b/apps/browser/src/popup/app.module.ts
@@ -87,7 +87,7 @@ import { PrivateModeWarningComponent } from "./components/private-mode-warning.c
import { SendListComponent } from "./components/send-list.component";
import { SetPinComponent } from "./components/set-pin.component";
import { UserVerificationComponent } from "./components/user-verification.component";
-import { Fido2Module } from "./fido2/fido2.module";
+import { Fido2Component } from "./fido2/fido2.component";
import { GeneratorComponent } from "./generator/generator.component";
import { PasswordGeneratorHistoryComponent } from "./generator/password-generator-history.component";
import { EffluxDatesComponent as SendEffluxDatesComponent } from "./send/efflux-dates.component";
@@ -193,7 +193,6 @@ registerLocaleData(localeZhTw, "zh-TW");
ReactiveFormsModule,
ScrollingModule,
ServicesModule,
- Fido2Module,
],
declarations: [
ActionButtonsComponent,
@@ -246,6 +245,7 @@ registerLocaleData(localeZhTw, "zh-TW");
RemovePasswordComponent,
VaultSelectComponent,
AboutComponent,
+ Fido2Component,
],
providers: [CurrencyPipe, DatePipe],
bootstrap: [AppComponent],
diff --git a/apps/browser/src/popup/fido2/fido2.component.html b/apps/browser/src/popup/fido2/fido2.component.html
index efed0eb967d..e47d4c9aefd 100644
--- a/apps/browser/src/popup/fido2/fido2.component.html
+++ b/apps/browser/src/popup/fido2/fido2.component.html
@@ -1,16 +1,23 @@
-
-
- A site is asking for authentication
-
-
- A site wants to create a new passkey in your vault
-
-
-
-
-
+
+
+
+ A site is asking for authentication
+
+
+
+ A site wants to create a new passkey in your vault
+
+
+
+
+
+
diff --git a/apps/browser/src/popup/fido2/fido2.component.ts b/apps/browser/src/popup/fido2/fido2.component.ts
index 7695001dbad..3bf346a7cba 100644
--- a/apps/browser/src/popup/fido2/fido2.component.ts
+++ b/apps/browser/src/popup/fido2/fido2.component.ts
@@ -1,5 +1,10 @@
-import { Component, HostListener } from "@angular/core";
+import { Component, HostListener, OnDestroy, OnInit } from "@angular/core";
import { ActivatedRoute } from "@angular/router";
+import { Subject, takeUntil } from "rxjs";
+
+import { CipherType } from "@bitwarden/common/enums/cipherType";
+import { CipherView } from "@bitwarden/common/models/view/cipher.view";
+import { Fido2KeyView } from "@bitwarden/common/models/view/fido2-key.view";
import {
BrowserFido2Message,
@@ -11,11 +16,25 @@ import {
templateUrl: "fido2.component.html",
styleUrls: [],
})
-export class Fido2Component {
+export class Fido2Component implements OnInit, OnDestroy {
+ private destroy$ = new Subject();
+
+ protected data?: BrowserFido2Message;
+ protected cipher?: CipherView;
+
constructor(private activatedRoute: ActivatedRoute) {}
- get data() {
- return this.activatedRoute.snapshot.queryParams as BrowserFido2Message;
+ ngOnInit(): void {
+ this.activatedRoute.queryParamMap.pipe(takeUntil(this.destroy$)).subscribe((queryParamMap) => {
+ this.data = JSON.parse(queryParamMap.get("data"));
+
+ if (this.data?.type === "ConfirmNewCredentialRequest") {
+ this.cipher = new CipherView();
+ this.cipher.name = this.data.name;
+ this.cipher.type = CipherType.Fido2Key;
+ this.cipher.fido2Key = new Fido2KeyView();
+ }
+ });
}
async accept() {
@@ -56,4 +75,9 @@ export class Fido2Component {
fallbackRequested: fallback,
});
}
+
+ ngOnDestroy(): void {
+ this.destroy$.next();
+ this.destroy$.complete();
+ }
}
diff --git a/apps/browser/src/popup/fido2/fido2.module.ts b/apps/browser/src/popup/fido2/fido2.module.ts
deleted file mode 100644
index d052dcb0987..00000000000
--- a/apps/browser/src/popup/fido2/fido2.module.ts
+++ /dev/null
@@ -1,11 +0,0 @@
-import { CommonModule } from "@angular/common";
-import { NgModule } from "@angular/core";
-
-import { Fido2Component } from "./fido2.component";
-
-@NgModule({
- imports: [CommonModule],
- declarations: [Fido2Component],
- exports: [Fido2Component],
-})
-export class Fido2Module {}
diff --git a/apps/browser/src/services/fido2/browser-fido2-user-interface.service.ts b/apps/browser/src/services/fido2/browser-fido2-user-interface.service.ts
index e8f18923f52..603ed6c4945 100644
--- a/apps/browser/src/services/fido2/browser-fido2-user-interface.service.ts
+++ b/apps/browser/src/services/fido2/browser-fido2-user-interface.service.ts
@@ -1,6 +1,9 @@
import { filter, first, lastValueFrom, Subject, takeUntil } from "rxjs";
-import { Fido2UserInterfaceService as Fido2UserInterfaceServiceAbstraction } from "@bitwarden/common/abstractions/fido2/fido2-user-interface.service.abstraction";
+import {
+ Fido2UserInterfaceService as Fido2UserInterfaceServiceAbstraction,
+ NewCredentialParams,
+} from "@bitwarden/common/abstractions/fido2/fido2-user-interface.service.abstraction";
import { Utils } from "@bitwarden/common/misc/utils";
import { RequestAbortedError } from "../../../../../libs/common/src/abstractions/fido2/fido2.service.abstraction";
@@ -18,6 +21,7 @@ export type BrowserFido2Message = { requestId: string } & (
}
| {
type: "ConfirmNewCredentialRequest";
+ name: string;
}
| {
type: "ConfirmNewCredentialResponse";
@@ -51,7 +55,7 @@ export class BrowserFido2UserInterfaceService implements Fido2UserInterfaceServi
async verifyPresence(): Promise {
const requestId = Utils.newGuid();
const data: BrowserFido2Message = { type: "VerifyUserRequest", requestId };
- const queryParams = new URLSearchParams(data).toString();
+ const queryParams = new URLSearchParams({ data: JSON.stringify(data) }).toString();
this.popupUtilsService.popOut(
null,
`popup/index.html?uilocation=popout#/fido2?${queryParams}`,
@@ -77,10 +81,10 @@ export class BrowserFido2UserInterfaceService implements Fido2UserInterfaceServi
return false;
}
- async confirmNewCredential(): Promise {
+ async confirmNewCredential({ name }: NewCredentialParams): Promise {
const requestId = Utils.newGuid();
- const data: BrowserFido2Message = { type: "ConfirmNewCredentialRequest", requestId };
- const queryParams = new URLSearchParams(data).toString();
+ const data: BrowserFido2Message = { type: "ConfirmNewCredentialRequest", requestId, name };
+ const queryParams = new URLSearchParams({ data: JSON.stringify(data) }).toString();
this.popupUtilsService.popOut(
null,
`popup/index.html?uilocation=popout#/fido2?${queryParams}`,
diff --git a/libs/common/src/abstractions/fido2/fido2-user-interface.service.abstraction.ts b/libs/common/src/abstractions/fido2/fido2-user-interface.service.abstraction.ts
index 6dfed28d5f0..93a87534f07 100644
--- a/libs/common/src/abstractions/fido2/fido2-user-interface.service.abstraction.ts
+++ b/libs/common/src/abstractions/fido2/fido2-user-interface.service.abstraction.ts
@@ -1,5 +1,9 @@
+export interface NewCredentialParams {
+ name: string;
+}
+
export abstract class Fido2UserInterfaceService {
verifyUser: () => Promise;
verifyPresence: () => Promise;
- confirmNewCredential: () => Promise;
+ confirmNewCredential: (params: NewCredentialParams) => Promise;
}
diff --git a/libs/common/src/services/fido2/fido2.service.ts b/libs/common/src/services/fido2/fido2.service.ts
index 098b5659e44..8c38d6be0c4 100644
--- a/libs/common/src/services/fido2/fido2.service.ts
+++ b/libs/common/src/services/fido2/fido2.service.ts
@@ -42,7 +42,9 @@ export class Fido2Service implements Fido2ServiceAbstraction {
async createCredential(
params: CredentialRegistrationParams
): Promise {
- const presence = await this.fido2UserInterfaceService.confirmNewCredential();
+ const presence = await this.fido2UserInterfaceService.confirmNewCredential({
+ name: params.origin,
+ });
// eslint-disable-next-line no-console
console.log("Fido2Service.createCredential", params);
@@ -123,14 +125,11 @@ export class Fido2Service implements Fido2ServiceAbstraction {
credential = await this.getCredentialByRp(params.rpId);
}
- console.log("Found credential: ", credential);
-
if (credential === undefined) {
throw new NoCredentialFoundError();
}
if (credential.origin !== params.origin) {
- console.error(`${params.origin} tried to use credential created by ${credential.origin}`);
throw new OriginMismatchError();
}
@@ -203,8 +202,6 @@ export class Fido2Service implements Fido2ServiceAbstraction {
view.fido2Key.rpId = credential.rpId;
view.fido2Key.userHandle = Fido2Utils.bufferToString(credential.userHandle);
- console.log("saving credential", { view, credential });
-
const cipher = await this.cipherService.encrypt(view);
await this.cipherService.createWithServer(cipher);
@@ -237,22 +234,16 @@ interface AuthDataParams {
async function mapCipherViewToBitCredential(cipherView: CipherView): Promise {
const keyBuffer = Fido2Utils.stringToBuffer(cipherView.fido2Key.key);
- let privateKey;
- try {
- privateKey = await crypto.subtle.importKey(
- "pkcs8",
- keyBuffer,
- {
- name: "ECDSA",
- namedCurve: "P-256",
- },
- true,
- KeyUsages
- );
- } catch (err) {
- console.log("Error importing key", { err });
- throw err;
- }
+ const privateKey = await crypto.subtle.importKey(
+ "pkcs8",
+ keyBuffer,
+ {
+ name: "ECDSA",
+ namedCurve: "P-256",
+ },
+ true,
+ KeyUsages
+ );
return {
credentialId: new CredentialId(cipherView.id),