1
0
mirror of https://github.com/bitwarden/browser synced 2026-02-02 09:43:29 +00:00

Cleaned up napi types

This commit is contained in:
Anders Åberg
2025-07-07 10:48:03 +02:00
parent 9001967eea
commit af987a6ba7
4 changed files with 218 additions and 163 deletions

View File

@@ -3,10 +3,6 @@
/* auto-generated by NAPI-RS */
export interface PasskeyRequestEvent {
requestType: string
requestJson: string
}
export declare namespace passwords {
/** Fetch the stored password from the keychain. */
export function getPassword(service: string, account: string): Promise<string>
@@ -190,6 +186,10 @@ export declare namespace crypto {
export function argon2(secret: Buffer, salt: Buffer, iterations: number, memory: number, parallelism: number): Promise<Buffer>
}
export declare namespace passkey_authenticator {
export interface PasskeyRequestEvent {
requestType: string
requestJson: string
}
export interface SyncedCredential {
credentialId: string
rpId: string

View File

@@ -810,13 +810,14 @@ pub mod crypto {
#[napi]
pub mod passkey_authenticator {
use napi::threadsafe_function::{
ErrorStrategy::CalleeHandled, ThreadsafeFunction,
};
use serde_json;
use napi::threadsafe_function::{ErrorStrategy::CalleeHandled, ThreadsafeFunction};
// Re-export the platform-specific types
pub use crate::passkey_authenticator_internal::PasskeyRequestEvent;
#[napi(object)]
#[derive(Debug)]
pub struct PasskeyRequestEvent {
pub request_type: String,
pub request_json: String,
}
#[napi(object)]
#[derive(serde::Serialize, serde::Deserialize)]
@@ -827,34 +828,6 @@ pub mod passkey_authenticator {
pub user_id: String, // base64url encoded
}
impl From<windows_plugin_authenticator::SyncedCredential> for SyncedCredential {
fn from(cred: windows_plugin_authenticator::SyncedCredential) -> Self {
use base64::Engine;
Self {
credential_id: base64::engine::general_purpose::URL_SAFE_NO_PAD.encode(&cred.credential_id),
rp_id: cred.rp_id,
user_name: cred.user_name,
user_id: base64::engine::general_purpose::URL_SAFE_NO_PAD.encode(&cred.user_id),
}
}
}
impl From<SyncedCredential> for windows_plugin_authenticator::SyncedCredential {
fn from(cred: SyncedCredential) -> Self {
use base64::Engine;
Self {
credential_id: base64::engine::general_purpose::URL_SAFE_NO_PAD
.decode(&cred.credential_id)
.unwrap_or_default(),
rp_id: cred.rp_id,
user_name: cred.user_name,
user_id: base64::engine::general_purpose::URL_SAFE_NO_PAD
.decode(&cred.user_id)
.unwrap_or_default(),
}
}
}
#[napi(object)]
#[derive(serde::Serialize, serde::Deserialize)]
#[serde(rename_all = "camelCase")]
@@ -923,7 +896,6 @@ pub mod passkey_authenticator {
pub message: String,
}
#[napi]
pub fn register() -> napi::Result<()> {
crate::passkey_authenticator_internal::register().map_err(|e| {
@@ -933,7 +905,9 @@ pub mod passkey_authenticator {
#[napi]
pub async fn on_request(
#[napi(ts_arg_type = "(error: null | Error, event: PasskeyRequestEvent) => Promise<string>")]
#[napi(
ts_arg_type = "(error: null | Error, event: PasskeyRequestEvent) => Promise<string>"
)]
callback: ThreadsafeFunction<PasskeyRequestEvent, CalleeHandled>,
) -> napi::Result<String> {
crate::passkey_authenticator_internal::on_request(callback).await
@@ -941,81 +915,12 @@ pub mod passkey_authenticator {
#[napi]
pub fn sync_credentials_to_windows(credentials: Vec<SyncedCredential>) -> napi::Result<()> {
const PLUGIN_CLSID: &str = "0f7dc5d9-69ce-4652-8572-6877fd695062";
log::info!("[NAPI] sync_credentials_to_windows called with {} credentials", credentials.len());
// Log each credential being synced (with truncated IDs for security)
for (i, cred) in credentials.iter().enumerate() {
let truncated_cred_id = if cred.credential_id.len() > 16 {
format!("{}...", &cred.credential_id[..16])
} else {
cred.credential_id.clone()
};
let truncated_user_id = if cred.user_id.len() > 16 {
format!("{}...", &cred.user_id[..16])
} else {
cred.user_id.clone()
};
log::info!("[NAPI] Credential {}: RP={}, User={}, CredID={}, UserID={}",
i + 1, cred.rp_id, cred.user_name, truncated_cred_id, truncated_user_id);
}
// Convert NAPI types to internal types using From trait
let internal_credentials: Vec<windows_plugin_authenticator::SyncedCredential> = credentials
.into_iter()
.map(|cred| cred.into())
.collect();
log::info!("[NAPI] Calling Windows Plugin Authenticator sync with CLSID: {}", PLUGIN_CLSID);
let result = windows_plugin_authenticator::sync_credentials_to_windows(internal_credentials, PLUGIN_CLSID);
match &result {
Ok(()) => log::info!("[NAPI] sync_credentials_to_windows completed successfully"),
Err(e) => log::error!("[NAPI] sync_credentials_to_windows failed: {}", e),
}
result.map_err(|e| napi::Error::from_reason(format!("Sync credentials failed: {}", e)))
crate::passkey_authenticator_internal::sync_credentials_to_windows(credentials)
}
#[napi]
pub fn get_credentials_from_windows() -> napi::Result<Vec<SyncedCredential>> {
const PLUGIN_CLSID: &str = "0f7dc5d9-69ce-4652-8572-6877fd695062";
log::info!("[NAPI] get_credentials_from_windows called with CLSID: {}", PLUGIN_CLSID);
let result = windows_plugin_authenticator::get_credentials_from_windows(PLUGIN_CLSID);
let internal_credentials = match &result {
Ok(creds) => {
log::info!("[NAPI] Retrieved {} credentials from Windows", creds.len());
result.map_err(|e| napi::Error::from_reason(format!("Get credentials failed: {}", e)))?
}
Err(e) => {
log::error!("[NAPI] get_credentials_from_windows failed: {}", e);
return Err(napi::Error::from_reason(format!("Get credentials failed: {}", e)));
}
};
// Convert internal types to NAPI types using From trait
let napi_credentials: Vec<SyncedCredential> = internal_credentials
.into_iter()
.enumerate()
.map(|(i, cred)| {
let result_cred: SyncedCredential = cred.into();
let truncated_cred_id = if result_cred.credential_id.len() > 16 {
format!("{}...", &result_cred.credential_id[..16])
} else {
result_cred.credential_id.clone()
};
log::info!("[NAPI] Retrieved credential {}: RP={}, User={}, CredID={}",
i + 1, result_cred.rp_id, result_cred.user_name, truncated_cred_id);
result_cred
})
.collect();
log::info!("[NAPI] get_credentials_from_windows completed successfully, returning {} credentials", napi_credentials.len());
Ok(napi_credentials)
crate::passkey_authenticator_internal::get_credentials_from_windows()
}
}

View File

@@ -1,15 +1,8 @@
use anyhow::{bail, Result};
use napi::threadsafe_function::{
ErrorStrategy::CalleeHandled, ThreadsafeFunction,
};
use napi::threadsafe_function::{ErrorStrategy::CalleeHandled, ThreadsafeFunction};
#[napi(object)]
#[derive(Debug)]
pub struct PasskeyRequestEvent {
pub operation: String,
pub rpid: String,
pub transaction_id: String,
}
// Use the PasskeyRequestEvent from the parent module
pub use crate::passkey_authenticator::{PasskeyRequestEvent, SyncedCredential};
pub fn register() -> Result<()> {
bail!("Not implemented")
@@ -18,5 +11,19 @@ pub fn register() -> Result<()> {
pub async fn on_request(
_callback: ThreadsafeFunction<PasskeyRequestEvent, CalleeHandled>,
) -> napi::Result<String> {
Err(napi::Error::from_reason("Passkey authenticator is not supported on this platform".to_string()))
Err(napi::Error::from_reason(
"Passkey authenticator is not supported on this platform",
))
}
pub fn sync_credentials_to_windows(_credentials: Vec<SyncedCredential>) -> napi::Result<()> {
Err(napi::Error::from_reason(
"Windows credential sync not supported on this platform",
))
}
pub fn get_credentials_from_windows() -> napi::Result<Vec<SyncedCredential>> {
Err(napi::Error::from_reason(
"Windows credential retrieval not supported on this platform",
))
}

View File

@@ -1,18 +1,17 @@
use anyhow::{anyhow, Result};
use napi::{bindgen_prelude::Promise, threadsafe_function::{
ErrorStrategy::CalleeHandled, ThreadsafeFunction, ThreadsafeFunctionCallMode,
}, JsObject};
use tokio::sync::mpsc;
use napi::{
bindgen_prelude::Promise,
threadsafe_function::{
ErrorStrategy::CalleeHandled, ThreadsafeFunction, ThreadsafeFunctionCallMode,
},
JsObject,
};
use serde_json;
use tokio::sync::mpsc;
use windows_plugin_authenticator::util;
// Simple wrapper for passing JSON strings to TypeScript
#[napi(object)]
#[derive(Debug)]
pub struct PasskeyRequestEvent {
pub request_type: String,
pub request_json: String,
}
// Use the PasskeyRequestEvent from the parent module
pub use crate::passkey_authenticator::{PasskeyRequestEvent, SyncedCredential};
pub fn register() -> Result<()> {
windows_plugin_authenticator::register().map_err(|e| anyhow!(e))?;
@@ -24,59 +23,203 @@ pub async fn on_request(
callback: ThreadsafeFunction<PasskeyRequestEvent, CalleeHandled>,
) -> napi::Result<String> {
let (tx, mut rx) = mpsc::unbounded_channel();
// Set the sender in the Windows plugin authenticator
windows_plugin_authenticator::set_request_sender(tx);
// Spawn task to handle incoming events
tokio::spawn(async move {
while let Some(event) = rx.recv().await {
// The request is already serialized as JSON in the event
let request_json = event.request_json;
// Get the request type as a string
let request_type = match event.request_type {
windows_plugin_authenticator::RequestType::Assertion => "assertion".to_string(),
windows_plugin_authenticator::RequestType::Registration => "registration".to_string(),
windows_plugin_authenticator::RequestType::Registration => {
"registration".to_string()
}
windows_plugin_authenticator::RequestType::Sync => "sync".to_string(),
};
let napi_event = PasskeyRequestEvent { request_type, request_json };
let napi_event = PasskeyRequestEvent {
request_type,
request_json,
};
// Call the callback asynchronously and capture the return value
let promise_result: Result<Promise<String>, napi::Error> = callback.call_async(Ok(napi_event)).await;
let promise_result: Result<Promise<String>, napi::Error> =
callback.call_async(Ok(napi_event)).await;
// awai promse
match promise_result {
Ok(promise_result) => match promise_result.await {
Ok(result) => {
util::message(&format!("CALLBACK COMPLETED WITH RESPONSE: {}", result));
// Parse the JSON response directly back to Rust enum
let response: windows_plugin_authenticator::PasskeyResponse = match serde_json::from_str(&result) {
Ok(resp) => resp,
Err(e) => windows_plugin_authenticator::PasskeyResponse::Error {
message: format!("JSON parse error: {}", e),
}
};
let _ = event.response_sender.send(response);
}
Err(e) => {
eprintln!("Error calling passkey callback inner: {}", e);
let _ = event.response_sender.send(windows_plugin_authenticator::PasskeyResponse::Error {
message: format!("Inner Callback error: {}", e),
});
}
}
util::message(&format!("CALLBACK COMPLETED WITH RESPONSE: {}", result));
// Parse the JSON response directly back to Rust enum
let response: windows_plugin_authenticator::PasskeyResponse =
match serde_json::from_str(&result) {
Ok(resp) => resp,
Err(e) => windows_plugin_authenticator::PasskeyResponse::Error {
message: format!("JSON parse error: {}", e),
},
};
let _ = event.response_sender.send(response);
}
Err(e) => {
eprintln!("Error calling passkey callback inner: {}", e);
let _ = event.response_sender.send(
windows_plugin_authenticator::PasskeyResponse::Error {
message: format!("Inner Callback error: {}", e),
},
);
}
},
Err(e) => {
eprintln!("Error calling passkey callback: {}", e);
let _ = event.response_sender.send(windows_plugin_authenticator::PasskeyResponse::Error {
message: format!("Callback error: {}", e),
});
let _ = event.response_sender.send(
windows_plugin_authenticator::PasskeyResponse::Error {
message: format!("Callback error: {}", e),
},
);
}
}
}
});
Ok("Event listener registered successfully".to_string())
}
impl From<windows_plugin_authenticator::SyncedCredential> for SyncedCredential {
fn from(cred: windows_plugin_authenticator::SyncedCredential) -> Self {
use base64::Engine;
Self {
credential_id: base64::engine::general_purpose::URL_SAFE_NO_PAD
.encode(&cred.credential_id),
rp_id: cred.rp_id,
user_name: cred.user_name,
user_id: base64::engine::general_purpose::URL_SAFE_NO_PAD.encode(&cred.user_id),
}
}
}
impl From<SyncedCredential> for windows_plugin_authenticator::SyncedCredential {
fn from(cred: SyncedCredential) -> Self {
use base64::Engine;
Self {
credential_id: base64::engine::general_purpose::URL_SAFE_NO_PAD
.decode(&cred.credential_id)
.unwrap_or_default(),
rp_id: cred.rp_id,
user_name: cred.user_name,
user_id: base64::engine::general_purpose::URL_SAFE_NO_PAD
.decode(&cred.user_id)
.unwrap_or_default(),
}
}
}
pub fn sync_credentials_to_windows(credentials: Vec<SyncedCredential>) -> napi::Result<()> {
const PLUGIN_CLSID: &str = "0f7dc5d9-69ce-4652-8572-6877fd695062";
log::info!(
"[NAPI] sync_credentials_to_windows called with {} credentials",
credentials.len()
);
// Log each credential being synced (with truncated IDs for security)
for (i, cred) in credentials.iter().enumerate() {
let truncated_cred_id = if cred.credential_id.len() > 16 {
format!("{}...", &cred.credential_id[..16])
} else {
cred.credential_id.clone()
};
let truncated_user_id = if cred.user_id.len() > 16 {
format!("{}...", &cred.user_id[..16])
} else {
cred.user_id.clone()
};
log::info!(
"[NAPI] Credential {}: RP={}, User={}, CredID={}, UserID={}",
i + 1,
cred.rp_id,
cred.user_name,
truncated_cred_id,
truncated_user_id
);
}
// Convert NAPI types to internal types using From trait
let internal_credentials: Vec<windows_plugin_authenticator::SyncedCredential> =
credentials.into_iter().map(|cred| cred.into()).collect();
log::info!(
"[NAPI] Calling Windows Plugin Authenticator sync with CLSID: {}",
PLUGIN_CLSID
);
let result = windows_plugin_authenticator::sync_credentials_to_windows(
internal_credentials,
PLUGIN_CLSID,
);
match &result {
Ok(()) => log::info!("[NAPI] sync_credentials_to_windows completed successfully"),
Err(e) => log::error!("[NAPI] sync_credentials_to_windows failed: {}", e),
}
result.map_err(|e| napi::Error::from_reason(format!("Sync credentials failed: {}", e)))
}
pub fn get_credentials_from_windows() -> napi::Result<Vec<SyncedCredential>> {
const PLUGIN_CLSID: &str = "0f7dc5d9-69ce-4652-8572-6877fd695062";
log::info!(
"[NAPI] get_credentials_from_windows called with CLSID: {}",
PLUGIN_CLSID
);
let result = windows_plugin_authenticator::get_credentials_from_windows(PLUGIN_CLSID);
let internal_credentials = match &result {
Ok(creds) => {
log::info!("[NAPI] Retrieved {} credentials from Windows", creds.len());
result
.map_err(|e| napi::Error::from_reason(format!("Get credentials failed: {}", e)))?
}
Err(e) => {
log::error!("[NAPI] get_credentials_from_windows failed: {}", e);
return Err(napi::Error::from_reason(format!(
"Get credentials failed: {}",
e
)));
}
};
// Convert internal types to NAPI types
let napi_credentials: Vec<SyncedCredential> = internal_credentials
.into_iter()
.enumerate()
.map(|(i, cred)| {
let result_cred: SyncedCredential = cred.into();
let truncated_cred_id = if result_cred.credential_id.len() > 16 {
format!("{}...", &result_cred.credential_id[..16])
} else {
result_cred.credential_id.clone()
};
log::info!(
"[NAPI] Retrieved credential {}: RP={}, User={}, CredID={}",
i + 1,
result_cred.rp_id,
result_cred.user_name,
truncated_cred_id
);
result_cred
})
.collect();
log::info!(
"[NAPI] get_credentials_from_windows completed successfully, returning {} credentials",
napi_credentials.len()
);
Ok(napi_credentials)
}