1
0
mirror of https://github.com/bitwarden/browser synced 2026-02-03 10:13:31 +00:00

Don't prompt for selecting FIDO credential twice on Windows

This commit is contained in:
Isaiah Inuwa
2025-11-08 23:50:04 -06:00
parent 1094136290
commit 0c248b04cc
4 changed files with 34 additions and 16 deletions

View File

@@ -176,8 +176,8 @@ export declare namespace autofill {
export interface PasskeyAssertionWithoutUserInterfaceRequest {
rpId: string
credentialId: Array<number>
userName: string
userHandle: Array<number>
userName?: string
userHandle?: Array<number>
recordIdentifier?: string
clientDataHash: Array<number>
userVerification: UserVerification

View File

@@ -713,8 +713,8 @@ pub mod autofill {
pub struct PasskeyAssertionWithoutUserInterfaceRequest {
pub rp_id: String,
pub credential_id: Vec<u8>,
pub user_name: String,
pub user_handle: Vec<u8>,
pub user_name: Option<String>,
pub user_handle: Option<Vec<u8>>,
pub record_identifier: Option<String>,
pub client_data_hash: Vec<u8>,
pub user_verification: UserVerification,

View File

@@ -7,15 +7,18 @@ use std::{
};
use windows_core::{s, HRESULT};
use crate::com_provider::{
parse_credential_list, WebAuthnPluginOperationRequest, WebAuthnPluginOperationResponse,
};
use crate::ipc2::{
PasskeyAssertionRequest, PasskeyAssertionResponse, Position, TimedCallback, UserVerification,
WindowsProviderClient,
};
use crate::util::{debug_log, delay_load, wstr_to_string};
use crate::webauthn::WEBAUTHN_CREDENTIAL_LIST;
use crate::{
com_provider::{
parse_credential_list, WebAuthnPluginOperationRequest, WebAuthnPluginOperationResponse,
},
ipc2::PasskeyAssertionWithoutUserInterfaceRequest,
};
// Windows API types for WebAuthn (from webauthn.h.sample)
#[repr(C)]
@@ -134,7 +137,22 @@ fn send_assertion_request(
.map_err(|err| format!("Failed to serialize assertion request: {err}"))?;
tracing::debug!(?request_json, "Sending assertion request");
let callback = Arc::new(TimedCallback::new());
ipc_client.prepare_passkey_assertion(request, callback.clone());
if request.allowed_credentials.len() == 1 {
// copying this into another struct because I'm too lazy to make an enum right now.
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,
};
ipc_client.prepare_passkey_assertion_without_user_interface(request, callback.clone());
} else {
ipc_client.prepare_passkey_assertion(request, callback.clone());
}
callback
.wait_for_response(Duration::from_secs(30))
.map_err(|_| "Registration request timed out".to_string())?

View File

@@ -18,14 +18,14 @@ pub struct PasskeyAssertionRequest {
#[derive(Debug, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct PasskeyAssertionWithoutUserInterfaceRequest {
rp_id: String,
credential_id: Vec<u8>,
user_name: String,
user_handle: Vec<u8>,
record_identifier: Option<String>,
client_data_hash: Vec<u8>,
user_verification: UserVerification,
window_xy: Position,
pub rp_id: String,
pub credential_id: Vec<u8>,
// pub user_name: String,
// pub user_handle: Vec<u8>,
// pub record_identifier: Option<String>,
pub client_data_hash: Vec<u8>,
pub user_verification: UserVerification,
pub window_xy: Position,
}
#[derive(Debug, Serialize, Deserialize)]