diff --git a/apps/desktop/desktop_native/napi/index.d.ts b/apps/desktop/desktop_native/napi/index.d.ts index 344bcb7defc..f58573d8dde 100644 --- a/apps/desktop/desktop_native/napi/index.d.ts +++ b/apps/desktop/desktop_native/napi/index.d.ts @@ -165,7 +165,7 @@ export declare namespace autofill { supportedAlgorithms: Array windowXy: Position excludedCredentials: Array> - context?: Array + context?: string } export interface PasskeyRegistrationResponse { rpId: string @@ -179,7 +179,7 @@ export declare namespace autofill { userVerification: UserVerification allowedCredentials: Array> windowXy: Position - context?: Array + context?: string } export interface PasskeyAssertionWithoutUserInterfaceRequest { rpId: string @@ -190,7 +190,7 @@ export declare namespace autofill { clientDataHash: Array userVerification: UserVerification windowXy: Position - context?: Array + context?: string } export interface NativeStatus { key: string diff --git a/apps/desktop/desktop_native/napi/src/lib.rs b/apps/desktop/desktop_native/napi/src/lib.rs index d9bfb342bb2..ee2b2aaebf9 100644 --- a/apps/desktop/desktop_native/napi/src/lib.rs +++ b/apps/desktop/desktop_native/napi/src/lib.rs @@ -695,7 +695,7 @@ pub mod autofill { pub supported_algorithms: Vec, pub window_xy: Position, pub excluded_credentials: Vec>, - pub context: Option>, + pub context: Option, } #[napi(object)] @@ -717,7 +717,7 @@ pub mod autofill { pub user_verification: UserVerification, pub allowed_credentials: Vec>, pub window_xy: Position, - pub context: Option>, + pub context: Option, //extension_input: Vec, TODO: Implement support for extensions } @@ -733,7 +733,7 @@ pub mod autofill { pub client_data_hash: Vec, pub user_verification: UserVerification, pub window_xy: Position, - pub context: Option>, + pub context: Option, } #[napi(object)] diff --git a/apps/desktop/desktop_native/windows_plugin_authenticator/src/assert.rs b/apps/desktop/desktop_native/windows_plugin_authenticator/src/assert.rs index 579faddc841..63be191155a 100644 --- a/apps/desktop/desktop_native/windows_plugin_authenticator/src/assert.rs +++ b/apps/desktop/desktop_native/windows_plugin_authenticator/src/assert.rs @@ -12,7 +12,7 @@ use crate::{ PasskeyAssertionWithoutUserInterfaceRequest, Position, TimedCallback, UserVerification, WindowsProviderClient, }, - util::HwndExt, + util::{create_context_string, HwndExt}, }; pub fn get_assertion( @@ -44,7 +44,6 @@ pub fn get_assertion( .map(|id| id.to_vec()) .collect(); - let transaction_id = request.transaction_id.to_u128().to_le_bytes().to_vec(); let client_pos = request .window_handle .center_position() @@ -55,6 +54,7 @@ pub fn get_assertion( rp_id, allowed_credential_ids ); + let context = create_context_string(request.transaction_id); // Send assertion request let assertion_request = PasskeyAssertionRequest { @@ -66,7 +66,7 @@ pub fn get_assertion( x: client_pos.0, y: client_pos.1, }, - context: transaction_id, + context, }; let passkey_response = send_assertion_request(ipc_client, assertion_request, cancellation_token) @@ -107,9 +107,6 @@ fn send_assertion_request( let request = PasskeyAssertionWithoutUserInterfaceRequest { rp_id: request.rp_id, credential_id: request.allowed_credentials[0].clone(), - // user_name: request.user_name, - // user_handle: request., - // record_identifier: todo!(), client_data_hash: request.client_data_hash, user_verification: request.user_verification, window_xy: request.window_xy, diff --git a/apps/desktop/desktop_native/windows_plugin_authenticator/src/ipc2/assertion.rs b/apps/desktop/desktop_native/windows_plugin_authenticator/src/ipc2/assertion.rs index 660a5971a37..3820d3c0b9c 100644 --- a/apps/desktop/desktop_native/windows_plugin_authenticator/src/ipc2/assertion.rs +++ b/apps/desktop/desktop_native/windows_plugin_authenticator/src/ipc2/assertion.rs @@ -12,7 +12,7 @@ pub struct PasskeyAssertionRequest { pub user_verification: UserVerification, pub allowed_credentials: Vec>, pub window_xy: Position, - pub context: Vec, + pub context: String, // pub extension_input: Vec, TODO: Implement support for extensions } @@ -21,13 +21,10 @@ pub struct PasskeyAssertionRequest { pub struct PasskeyAssertionWithoutUserInterfaceRequest { pub rp_id: String, pub credential_id: Vec, - // pub user_name: String, - // pub user_handle: Vec, - // pub record_identifier: Option, pub client_data_hash: Vec, pub user_verification: UserVerification, pub window_xy: Position, - pub context: Vec, + pub context: String, } #[derive(Debug, Serialize, Deserialize)] diff --git a/apps/desktop/desktop_native/windows_plugin_authenticator/src/ipc2/mod.rs b/apps/desktop/desktop_native/windows_plugin_authenticator/src/ipc2/mod.rs index bd44666fcd3..4522005bbcf 100644 --- a/apps/desktop/desktop_native/windows_plugin_authenticator/src/ipc2/mod.rs +++ b/apps/desktop/desktop_native/windows_plugin_authenticator/src/ipc2/mod.rs @@ -4,7 +4,7 @@ use std::{ fmt::Display, sync::{ atomic::AtomicU32, - mpsc::{self, Receiver, RecvError, RecvTimeoutError, Sender}, + mpsc::{self, Receiver, RecvTimeoutError, Sender}, Arc, Mutex, }, time::{Duration, Instant}, diff --git a/apps/desktop/desktop_native/windows_plugin_authenticator/src/ipc2/registration.rs b/apps/desktop/desktop_native/windows_plugin_authenticator/src/ipc2/registration.rs index f9ac9033155..1c10ecb95d0 100644 --- a/apps/desktop/desktop_native/windows_plugin_authenticator/src/ipc2/registration.rs +++ b/apps/desktop/desktop_native/windows_plugin_authenticator/src/ipc2/registration.rs @@ -15,7 +15,7 @@ pub struct PasskeyRegistrationRequest { pub supported_algorithms: Vec, pub window_xy: Position, pub excluded_credentials: Vec>, - pub context: Vec, + pub context: String, } #[derive(Debug, Serialize, Deserialize)] diff --git a/apps/desktop/desktop_native/windows_plugin_authenticator/src/make_credential.rs b/apps/desktop/desktop_native/windows_plugin_authenticator/src/make_credential.rs index 53bbdfc1a20..6abe52f8867 100644 --- a/apps/desktop/desktop_native/windows_plugin_authenticator/src/make_credential.rs +++ b/apps/desktop/desktop_native/windows_plugin_authenticator/src/make_credential.rs @@ -1,6 +1,5 @@ use serde_json; use std::collections::HashMap; -use std::sync::mpsc::TryRecvError; use std::sync::{mpsc::Receiver, Arc}; use std::time::Duration; @@ -10,6 +9,7 @@ use win_webauthn::{ }; use crate::ipc2::CallbackError; +use crate::util::create_context_string; use crate::{ ipc2::{ PasskeyRegistrationRequest, PasskeyRegistrationResponse, Position, TimedCallback, @@ -87,12 +87,13 @@ pub fn make_credential( ); } - let transaction_id = request.transaction_id.to_u128().to_le_bytes().to_vec(); let client_pos = request .window_handle .center_position() .unwrap_or((640, 480)); + let context = create_context_string(request.transaction_id); + // Create Windows registration request let registration_request = PasskeyRegistrationRequest { rp_id: rpid.clone(), @@ -107,7 +108,7 @@ pub fn make_credential( x: client_pos.0, y: client_pos.1, }, - context: transaction_id, + context, }; tracing::debug!( diff --git a/apps/desktop/desktop_native/windows_plugin_authenticator/src/util.rs b/apps/desktop/desktop_native/windows_plugin_authenticator/src/util.rs index 396533f3998..3e7f5df5f7c 100644 --- a/apps/desktop/desktop_native/windows_plugin_authenticator/src/util.rs +++ b/apps/desktop/desktop_native/windows_plugin_authenticator/src/util.rs @@ -1,5 +1,11 @@ -use windows::Win32::UI::HiDpi::GetDpiForWindow; -use windows::Win32::{Foundation::*, UI::WindowsAndMessaging::GetWindowRect}; +use base64::engine::{general_purpose::STANDARD, Engine as _}; +use windows::{ + core::GUID, + Win32::{ + Foundation::*, + UI::{HiDpi::GetDpiForWindow, WindowsAndMessaging::GetWindowRect}, + }, +}; const BASE_DPI: u32 = 96; @@ -34,3 +40,7 @@ impl HwndExt for HWND { } } } + +pub fn create_context_string(transaction_id: GUID) -> String { + STANDARD.encode(transaction_id.to_u128().to_le_bytes().to_vec()) +} diff --git a/apps/desktop/src/autofill/services/desktop-autofill.service.ts b/apps/desktop/src/autofill/services/desktop-autofill.service.ts index 952e4bde04a..51cae002eda 100644 --- a/apps/desktop/src/autofill/services/desktop-autofill.service.ts +++ b/apps/desktop/src/autofill/services/desktop-autofill.service.ts @@ -211,20 +211,16 @@ export class DesktopAutofillService implements OnDestroy { this.logService.debug("listenPasskeyRegistration2", this.convertRegistrationRequest(request)); const controller = new AbortController(); - let requestId = request.context ? this.contextToRequestId(request.context) : null; - this.logService.debug("Request context:", requestId) - if (requestId) { - this.inFlightRequests[requestId] = controller; + if (request.context) { + this.inFlightRequests[request.context] = controller; } - const ctx = request.context ? new Uint8Array(request.context).buffer : null; - try { const response = await this.fido2AuthenticatorService.makeCredential( this.convertRegistrationRequest(request), { windowXy: request.windowXy }, controller, - ctx + request.context, ); this.logService.debug("Sending registration response to plugin via callback"); @@ -234,8 +230,8 @@ export class DesktopAutofillService implements OnDestroy { callback(error, null); } finally { - if (requestId) { - delete this.inFlightRequests[requestId]; + if (request.context) { + delete this.inFlightRequests[request.context]; } } this.logService.info("Passkey registration completed.") @@ -259,9 +255,8 @@ export class DesktopAutofillService implements OnDestroy { ); const controller = new AbortController(); - let requestId = request.context ? this.contextToRequestId(request.context) : null; - if (requestId) { - this.inFlightRequests[requestId] = controller; + if (request.context) { + this.inFlightRequests[request.context] = controller; } try { @@ -297,13 +292,12 @@ export class DesktopAutofillService implements OnDestroy { new Uint8Array(parseCredentialId(decrypted.login.fido2Credentials?.[0].credentialId)), ); } - const ctx = request.context ? new Uint8Array(request.context).buffer : null; const response = await this.fido2AuthenticatorService.getAssertion( this.convertAssertionRequest(request, true), { windowXy: request.windowXy }, controller, - ctx + request.context ); callback(null, this.convertAssertionResponse(request, response)); @@ -313,8 +307,8 @@ export class DesktopAutofillService implements OnDestroy { return; } finally { - if (requestId) { - delete this.inFlightRequests[requestId]; + if (request.context) { + delete this.inFlightRequests[request.context]; } } }, @@ -330,11 +324,9 @@ export class DesktopAutofillService implements OnDestroy { } this.logService.debug("listenPasskeyAssertion", clientId, sequenceNumber, request); - const ctx = request.context ? new Uint8Array(request.context).buffer : null; const controller = new AbortController(); - let requestId = request.context ? this.contextToRequestId(request.context) : null; - if (requestId) { - this.inFlightRequests[requestId] = controller; + if (request.context) { + this.inFlightRequests[request.context] = controller; } try { @@ -342,7 +334,7 @@ export class DesktopAutofillService implements OnDestroy { this.convertAssertionRequest(request), { windowXy: request.windowXy }, controller, - ctx + request.context, ); callback(null, this.convertAssertionResponse(request, response)); @@ -351,8 +343,8 @@ export class DesktopAutofillService implements OnDestroy { callback(error, null); } finally { - if (requestId) { - delete this.inFlightRequests[requestId]; + if (request.context) { + delete this.inFlightRequests[request.context]; } } }); @@ -500,12 +492,6 @@ export class DesktopAutofillService implements OnDestroy { }; } - private contextToRequestId(context: number[]): string { - const buf = new Uint8Array(context).buffer; - const requestId = Utils.fromBufferToB64(buf); - return requestId - } - ngOnDestroy(): void { this.destroy$.next(); this.destroy$.complete(); diff --git a/apps/desktop/src/autofill/services/desktop-fido2-user-interface.service.ts b/apps/desktop/src/autofill/services/desktop-fido2-user-interface.service.ts index 629c00881b5..e3bd37dbe6a 100644 --- a/apps/desktop/src/autofill/services/desktop-fido2-user-interface.service.ts +++ b/apps/desktop/src/autofill/services/desktop-fido2-user-interface.service.ts @@ -67,7 +67,7 @@ export class DesktopFido2UserInterfaceService fallbackSupported: boolean, nativeWindowObject: NativeWindowObject, abortController?: AbortController, - transactionContext?: ArrayBuffer, + transactionContext?: string, ): Promise { this.logService.debug("newSession", fallbackSupported, abortController, nativeWindowObject, transactionContext); const session = new DesktopFido2UserInterfaceSession( @@ -97,7 +97,7 @@ export class DesktopFido2UserInterfaceSession implements Fido2UserInterfaceSessi private desktopSettingsService: DesktopSettingsService, private windowObject: NativeWindowObject, private abortController: AbortController, - private transactionContext: ArrayBuffer, + private transactionContext: string, ) {} private confirmCredentialSubject = new Subject(); @@ -352,7 +352,7 @@ export class DesktopFido2UserInterfaceSession implements Fido2UserInterfaceSessi command: "user-verification", params: { windowHandle: Utils.fromBufferToB64(windowHandle), - transactionContext: Utils.fromBufferToB64(this.transactionContext), + transactionContext: this.transactionContext, username, displayHint, }, diff --git a/libs/common/src/platform/abstractions/fido2/fido2-authenticator.service.abstraction.ts b/libs/common/src/platform/abstractions/fido2/fido2-authenticator.service.abstraction.ts index 34c4e545eac..81f534a6cc3 100644 --- a/libs/common/src/platform/abstractions/fido2/fido2-authenticator.service.abstraction.ts +++ b/libs/common/src/platform/abstractions/fido2/fido2-authenticator.service.abstraction.ts @@ -19,7 +19,7 @@ export abstract class Fido2AuthenticatorService { params: Fido2AuthenticatorMakeCredentialsParams, window: ParentWindowReference, abortController?: AbortController, - transactionContext?: ArrayBuffer, + transactionContext?: string, ): Promise; /** @@ -34,7 +34,7 @@ export abstract class Fido2AuthenticatorService { params: Fido2AuthenticatorGetAssertionParams, window: ParentWindowReference, abortController?: AbortController, - transactionContext?: ArrayBuffer, + transactionContext?: string, ): Promise; /** diff --git a/libs/common/src/platform/abstractions/fido2/fido2-user-interface.service.abstraction.ts b/libs/common/src/platform/abstractions/fido2/fido2-user-interface.service.abstraction.ts index d949eec4326..a94e053d9db 100644 --- a/libs/common/src/platform/abstractions/fido2/fido2-user-interface.service.abstraction.ts +++ b/libs/common/src/platform/abstractions/fido2/fido2-user-interface.service.abstraction.ts @@ -71,7 +71,7 @@ export abstract class Fido2UserInterfaceService { fallbackSupported: boolean, window: ParentWindowReference, abortController?: AbortController, - transactionContext?: ArrayBuffer, + transactionContext?: string, ): Promise; } @@ -91,7 +91,6 @@ export abstract class Fido2UserInterfaceSession { * Ask the user to confirm the creation of a new credential. * * @param params The parameters to use when asking the user to confirm the creation of a new credential. - * @param abortController An abort controller that can be used to cancel/close the session. * @returns The ID of the cipher where the new credential should be saved. */ abstract confirmNewCredential( diff --git a/libs/common/src/platform/services/fido2/fido2-authenticator.service.ts b/libs/common/src/platform/services/fido2/fido2-authenticator.service.ts index 2f7fc9b0867..4f20eabc2b4 100644 --- a/libs/common/src/platform/services/fido2/fido2-authenticator.service.ts +++ b/libs/common/src/platform/services/fido2/fido2-authenticator.service.ts @@ -61,7 +61,7 @@ export class Fido2AuthenticatorService params: Fido2AuthenticatorMakeCredentialsParams, window: ParentWindowReference, abortController?: AbortController, - transactionContext?: ArrayBuffer, + transactionContext?: string, ): Promise { const userInterfaceSession = await this.userInterface.newSession( params.fallbackSupported, @@ -232,7 +232,7 @@ export class Fido2AuthenticatorService params: Fido2AuthenticatorGetAssertionParams, window: ParentWindowReference, abortController?: AbortController, - transactionContext?: ArrayBuffer, + transactionContext?: string, ): Promise { const userInterfaceSession = await this.userInterface.newSession( params.fallbackSupported,