mirror of
https://github.com/bitwarden/browser
synced 2026-02-09 21:20:27 +00:00
Use a string for transaction context everywhere
This commit is contained in:
6
apps/desktop/desktop_native/napi/index.d.ts
vendored
6
apps/desktop/desktop_native/napi/index.d.ts
vendored
@@ -165,7 +165,7 @@ export declare namespace autofill {
|
||||
supportedAlgorithms: Array<number>
|
||||
windowXy: Position
|
||||
excludedCredentials: Array<Array<number>>
|
||||
context?: Array<number>
|
||||
context?: string
|
||||
}
|
||||
export interface PasskeyRegistrationResponse {
|
||||
rpId: string
|
||||
@@ -179,7 +179,7 @@ export declare namespace autofill {
|
||||
userVerification: UserVerification
|
||||
allowedCredentials: Array<Array<number>>
|
||||
windowXy: Position
|
||||
context?: Array<number>
|
||||
context?: string
|
||||
}
|
||||
export interface PasskeyAssertionWithoutUserInterfaceRequest {
|
||||
rpId: string
|
||||
@@ -190,7 +190,7 @@ export declare namespace autofill {
|
||||
clientDataHash: Array<number>
|
||||
userVerification: UserVerification
|
||||
windowXy: Position
|
||||
context?: Array<number>
|
||||
context?: string
|
||||
}
|
||||
export interface NativeStatus {
|
||||
key: string
|
||||
|
||||
@@ -695,7 +695,7 @@ pub mod autofill {
|
||||
pub supported_algorithms: Vec<i32>,
|
||||
pub window_xy: Position,
|
||||
pub excluded_credentials: Vec<Vec<u8>>,
|
||||
pub context: Option<Vec<u8>>,
|
||||
pub context: Option<String>,
|
||||
}
|
||||
|
||||
#[napi(object)]
|
||||
@@ -717,7 +717,7 @@ pub mod autofill {
|
||||
pub user_verification: UserVerification,
|
||||
pub allowed_credentials: Vec<Vec<u8>>,
|
||||
pub window_xy: Position,
|
||||
pub context: Option<Vec<u8>>,
|
||||
pub context: Option<String>,
|
||||
//extension_input: Vec<u8>, TODO: Implement support for extensions
|
||||
}
|
||||
|
||||
@@ -733,7 +733,7 @@ pub mod autofill {
|
||||
pub client_data_hash: Vec<u8>,
|
||||
pub user_verification: UserVerification,
|
||||
pub window_xy: Position,
|
||||
pub context: Option<Vec<u8>>,
|
||||
pub context: Option<String>,
|
||||
}
|
||||
|
||||
#[napi(object)]
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -12,7 +12,7 @@ pub struct PasskeyAssertionRequest {
|
||||
pub user_verification: UserVerification,
|
||||
pub allowed_credentials: Vec<Vec<u8>>,
|
||||
pub window_xy: Position,
|
||||
pub context: Vec<u8>,
|
||||
pub context: String,
|
||||
// pub extension_input: Vec<u8>, TODO: Implement support for extensions
|
||||
}
|
||||
|
||||
@@ -21,13 +21,10 @@ pub struct PasskeyAssertionRequest {
|
||||
pub struct PasskeyAssertionWithoutUserInterfaceRequest {
|
||||
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,
|
||||
pub context: Vec<u8>,
|
||||
pub context: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
|
||||
@@ -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},
|
||||
|
||||
@@ -15,7 +15,7 @@ pub struct PasskeyRegistrationRequest {
|
||||
pub supported_algorithms: Vec<i32>,
|
||||
pub window_xy: Position,
|
||||
pub excluded_credentials: Vec<Vec<u8>>,
|
||||
pub context: Vec<u8>,
|
||||
pub context: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
|
||||
@@ -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!(
|
||||
|
||||
@@ -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())
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -67,7 +67,7 @@ export class DesktopFido2UserInterfaceService
|
||||
fallbackSupported: boolean,
|
||||
nativeWindowObject: NativeWindowObject,
|
||||
abortController?: AbortController,
|
||||
transactionContext?: ArrayBuffer,
|
||||
transactionContext?: string,
|
||||
): Promise<DesktopFido2UserInterfaceSession> {
|
||||
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<boolean>();
|
||||
@@ -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,
|
||||
},
|
||||
|
||||
@@ -19,7 +19,7 @@ export abstract class Fido2AuthenticatorService<ParentWindowReference> {
|
||||
params: Fido2AuthenticatorMakeCredentialsParams,
|
||||
window: ParentWindowReference,
|
||||
abortController?: AbortController,
|
||||
transactionContext?: ArrayBuffer,
|
||||
transactionContext?: string,
|
||||
): Promise<Fido2AuthenticatorMakeCredentialResult>;
|
||||
|
||||
/**
|
||||
@@ -34,7 +34,7 @@ export abstract class Fido2AuthenticatorService<ParentWindowReference> {
|
||||
params: Fido2AuthenticatorGetAssertionParams,
|
||||
window: ParentWindowReference,
|
||||
abortController?: AbortController,
|
||||
transactionContext?: ArrayBuffer,
|
||||
transactionContext?: string,
|
||||
): Promise<Fido2AuthenticatorGetAssertionResult>;
|
||||
|
||||
/**
|
||||
|
||||
@@ -71,7 +71,7 @@ export abstract class Fido2UserInterfaceService<ParentWindowReference> {
|
||||
fallbackSupported: boolean,
|
||||
window: ParentWindowReference,
|
||||
abortController?: AbortController,
|
||||
transactionContext?: ArrayBuffer,
|
||||
transactionContext?: string,
|
||||
): Promise<Fido2UserInterfaceSession>;
|
||||
}
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -61,7 +61,7 @@ export class Fido2AuthenticatorService<ParentWindowReference>
|
||||
params: Fido2AuthenticatorMakeCredentialsParams,
|
||||
window: ParentWindowReference,
|
||||
abortController?: AbortController,
|
||||
transactionContext?: ArrayBuffer,
|
||||
transactionContext?: string,
|
||||
): Promise<Fido2AuthenticatorMakeCredentialResult> {
|
||||
const userInterfaceSession = await this.userInterface.newSession(
|
||||
params.fallbackSupported,
|
||||
@@ -232,7 +232,7 @@ export class Fido2AuthenticatorService<ParentWindowReference>
|
||||
params: Fido2AuthenticatorGetAssertionParams,
|
||||
window: ParentWindowReference,
|
||||
abortController?: AbortController,
|
||||
transactionContext?: ArrayBuffer,
|
||||
transactionContext?: string,
|
||||
): Promise<Fido2AuthenticatorGetAssertionResult> {
|
||||
const userInterfaceSession = await this.userInterface.newSession(
|
||||
params.fallbackSupported,
|
||||
|
||||
Reference in New Issue
Block a user