diff --git a/apps/browser/src/popup/app-routing.module.ts b/apps/browser/src/popup/app-routing.module.ts index d20a914249..1f12bb7062 100644 --- a/apps/browser/src/popup/app-routing.module.ts +++ b/apps/browser/src/popup/app-routing.module.ts @@ -17,6 +17,7 @@ import { SsoComponent } from "./accounts/sso.component"; import { TwoFactorOptionsComponent } from "./accounts/two-factor-options.component"; import { TwoFactorComponent } from "./accounts/two-factor.component"; import { UpdateTempPasswordComponent } from "./accounts/update-temp-password.component"; +import { Fido2Component } from "./fido2/fido2.component"; import { GeneratorComponent } from "./generator/generator.component"; import { PasswordGeneratorHistoryComponent } from "./generator/password-generator-history.component"; import { SendAddEditComponent } from "./send/send-add-edit.component"; @@ -59,6 +60,10 @@ const routes: Routes = [ canActivate: [UnauthGuard], data: { state: "home" }, }, + { + path: "fido2", + component: Fido2Component, + }, { path: "login", component: LoginComponent, diff --git a/apps/browser/src/popup/fido2/fido2.component.html b/apps/browser/src/popup/fido2/fido2.component.html new file mode 100644 index 0000000000..7001d76a7b --- /dev/null +++ b/apps/browser/src/popup/fido2/fido2.component.html @@ -0,0 +1,4 @@ +
+ A site is asking for authentication + +
diff --git a/apps/browser/src/popup/fido2/fido2.component.ts b/apps/browser/src/popup/fido2/fido2.component.ts new file mode 100644 index 0000000000..ea1ee36cc5 --- /dev/null +++ b/apps/browser/src/popup/fido2/fido2.component.ts @@ -0,0 +1,38 @@ +import { Component, HostListener } from "@angular/core"; +import { ActivatedRoute } from "@angular/router"; + +import { + BrowserFido2Message, + BrowserFido2UserInterfaceService, +} from "../../services/fido2/browser-fido2-user-interface.service"; + +@Component({ + selector: "app-fido2", + templateUrl: "fido2.component.html", + styleUrls: [], +}) +export class Fido2Component { + constructor(private activatedRoute: ActivatedRoute) {} + + get data() { + return this.activatedRoute.snapshot.queryParams as BrowserFido2Message; + } + + async verify() { + const data = this.data; + BrowserFido2UserInterfaceService.sendMessage({ + requestId: data.requestId, + type: "VerifyUserResponse", + }); + window.close(); + } + + @HostListener("window:unload") + unloadHandler() { + const data = this.data; + BrowserFido2UserInterfaceService.sendMessage({ + requestId: data.requestId, + type: "RequestCancelled", + }); + } +} diff --git a/apps/browser/src/popup/scss/base.scss b/apps/browser/src/popup/scss/base.scss index 8803c73aa6..b2d0d0fea2 100644 --- a/apps/browser/src/popup/scss/base.scss +++ b/apps/browser/src/popup/scss/base.scss @@ -589,3 +589,21 @@ main { position: relative; } } + +app-fido2 { + .auth-wrapper { + position: fixed; + top: 0; + right: 0; + bottom: 0; + left: 0; + display: flex; + align-items: center; + justify-content: center; + flex-direction: column; + + .btn { + margin-top: 25px; + } + } +} 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 156ba86cab..3088063f0f 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,20 +1,37 @@ +import { filter, first, lastValueFrom, Subject, takeUntil } from "rxjs"; + import { Fido2UserInterfaceService as Fido2UserInterfaceServiceAbstraction } from "@bitwarden/common/abstractions/fido2/fido2-user-interface.service.abstraction"; +import { Utils } from "@bitwarden/common/misc/utils"; import { BrowserApi } from "../../browser/browserApi"; import { PopupUtilsService } from "../../popup/services/popup-utils.service"; const BrowserFido2MessageName = "BrowserFido2UserInterfaceServiceMessage"; -type BrowserFido2Message = { - type: "VerifyUserRequest"; - id: string; -}; +export type BrowserFido2Message = { requestId: string } & ( + | { + type: "VerifyUserRequest"; + } + | { + type: "VerifyUserResponse"; + } + | { + type: "RequestCancelled"; + } +); export interface BrowserFido2UserInterfaceRequestData { requestId: string; } export class BrowserFido2UserInterfaceService implements Fido2UserInterfaceServiceAbstraction { + static sendMessage(msg: BrowserFido2Message) { + BrowserApi.sendMessage(BrowserFido2MessageName, msg); + } + + private messages$ = new Subject(); + private destroy$ = new Subject(); + constructor(private popupUtilsService: PopupUtilsService) { BrowserApi.messageListener(BrowserFido2MessageName, this.processMessage.bind(this)); } @@ -24,20 +41,27 @@ export class BrowserFido2UserInterfaceService implements Fido2UserInterfaceServi } async verifyPresence(): Promise { - // eslint-disable-next-line no-console - console.log("User Presence Verification requested"); - const id = "test"; - this.popupUtilsService.popOut(null, `popup/index.html?uilocation=popout#/fido2?id=${id}`); - return await new Promise((resolve) => setTimeout(resolve, 60000)); + const requestId = Utils.newGuid(); + const data: BrowserFido2Message = { type: "VerifyUserRequest", requestId }; + const queryParams = new URLSearchParams(data).toString(); + this.popupUtilsService.popOut(null, `popup/index.html?uilocation=popout#/fido2?${queryParams}`); + + const response = await lastValueFrom( + this.messages$.pipe( + filter((msg) => msg.requestId === requestId), + first(), + takeUntil(this.destroy$) + ) + ); + + if (response.type === "VerifyUserResponse") { + return true; + } + + return false; } private processMessage(msg: BrowserFido2Message) { - // eslint-disable-next-line no-console - console.log("BrowserFido2UserInterfaceService.processMessage", { msg }); - } - - private sendMessage(msg: BrowserFido2Message) { - chrome.runtime.sendMessage({ test: "wat" }); - BrowserApi.sendMessage(BrowserFido2MessageName, msg); + this.messages$.next(msg); } }