-
Notifications
You must be signed in to change notification settings - Fork 1.3k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Create uniffi package and use it from the extension
- Loading branch information
1 parent
9fcc4f0
commit cb2f7c3
Showing
15 changed files
with
866 additions
and
13 deletions.
There are no files selected for viewing
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,3 @@ | ||
[workspace] | ||
resolver = "2" | ||
members = ["napi", "core", "proxy"] | ||
members = ["napi", "core", "proxy", "macos_provider"] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
BitwardenMacosProviderFFI.xcframework |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
[package] | ||
name = "macos_provider" | ||
license = "GPL-3.0" | ||
version = "0.0.0" | ||
edition = "2021" | ||
publish = false | ||
|
||
[[bin]] | ||
name = "uniffi-bindgen" | ||
path = "uniffi-bindgen.rs" | ||
|
||
[lib] | ||
crate-type = ["staticlib", "cdylib"] | ||
bench = false | ||
|
||
[dependencies] | ||
desktop_core = { path = "../core" } | ||
futures = "=0.3.31" | ||
log = "0.4.22" | ||
serde = { version = "1.0.205", features = ["derive"] } | ||
serde_json = "1.0.122" | ||
tokio = { version = "1.39.2", features = ["sync"] } | ||
tokio-util = "0.7.11" | ||
uniffi = { version = "0.28.0", features = ["cli"] } | ||
|
||
[target.'cfg(target_os = "macos")'.dependencies] | ||
oslog = "0.2.0" | ||
|
||
[build-dependencies] | ||
uniffi = { version = "0.28.0", features = ["build"] } |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
cd "$(dirname "$0")" | ||
|
||
rm -r BitwardenMacosProviderFFI.xcframework | ||
rm -r tmp | ||
|
||
mkdir -p ./tmp/target/universal-darwin/release/ | ||
|
||
|
||
cargo build --package macos_provider --target aarch64-apple-darwin --release | ||
cargo build --package macos_provider --target x86_64-apple-darwin --release | ||
|
||
# Create universal libraries | ||
lipo -create ../target/aarch64-apple-darwin/release/libmacos_provider.a \ | ||
../target/x86_64-apple-darwin/release/libmacos_provider.a \ | ||
-output ./tmp/target/universal-darwin/release/libmacos_provider.a | ||
|
||
# Generate swift bindings | ||
cargo run --bin uniffi-bindgen --features uniffi/cli generate \ | ||
../target/aarch64-apple-darwin/release/libmacos_provider.dylib \ | ||
--library \ | ||
--language swift \ | ||
--no-format \ | ||
--out-dir tmp/bindings | ||
|
||
# Move generated swift bindings | ||
mkdir -p ../../macos/autofill-extension/ | ||
mv ./tmp/bindings/*.swift ../../macos/autofill-extension/ | ||
|
||
# Massage the generated files to fit xcframework | ||
mkdir tmp/Headers | ||
mv ./tmp/bindings/*.h ./tmp/Headers/ | ||
cat ./tmp/bindings/*.modulemap > ./tmp/Headers/module.modulemap | ||
|
||
# Build xcframework | ||
xcodebuild -create-xcframework \ | ||
-library ./tmp/target/universal-darwin/release/libmacos_provider.a \ | ||
-headers ./tmp/Headers \ | ||
-output ./BitwardenMacosProviderFFI.xcframework | ||
|
||
# Cleanup temporary files | ||
rm -r tmp |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,176 @@ | ||
#![cfg(target_os = "macos")] | ||
|
||
use std::{ | ||
collections::HashMap, | ||
sync::{atomic::AtomicU32, Arc, Mutex}, | ||
}; | ||
|
||
use futures::FutureExt; | ||
use log::{error, info, warn}; | ||
use registration::{PasskeyRegistrationRequest, PreparePasskeyRegistrationCallback}; | ||
use serde::{de::DeserializeOwned, Deserialize, Serialize}; | ||
|
||
uniffi::setup_scaffolding!(); | ||
|
||
mod registration; | ||
|
||
#[derive(uniffi::Enum, Debug, Serialize, Deserialize)] | ||
pub enum UserVerification { | ||
Preferred, | ||
Required, | ||
Discouraged, | ||
} | ||
|
||
#[derive(uniffi::Error, Serialize, Deserialize)] | ||
pub enum BitwardenError { | ||
Internal(String), | ||
} | ||
|
||
// TODO: These have to be named differently than the actual Uniffi traits otherwise | ||
// the generated code will lead to ambiguous trait implementations | ||
// These are only used internally, so it doesn't matter that much | ||
trait Callback: Send + Sync { | ||
fn complete(&self, credential: serde_json::Value) -> Result<(), serde_json::Error>; | ||
fn error(&self, error: BitwardenError); | ||
} | ||
|
||
#[derive(uniffi::Object)] | ||
pub struct MacOSProviderClient { | ||
to_server_send: tokio::sync::mpsc::Sender<String>, | ||
|
||
// We need to keep track of the callbacks so we can call them when we receive a response | ||
response_callbacks_counter: AtomicU32, | ||
response_callbacks_queue: Arc<Mutex<HashMap<u32, Box<dyn Callback>>>>, | ||
} | ||
|
||
#[uniffi::export] | ||
impl MacOSProviderClient { | ||
#[uniffi::constructor] | ||
pub fn connect() -> Self { | ||
let _ = oslog::OsLogger::new("com.bitwarden.desktop.autofill-extension") | ||
.level_filter(log::LevelFilter::Trace) | ||
.init(); | ||
|
||
let (from_server_send, mut from_server_recv) = tokio::sync::mpsc::channel(32); | ||
let (to_server_send, to_server_recv) = tokio::sync::mpsc::channel(32); | ||
|
||
let client = MacOSProviderClient { | ||
to_server_send, | ||
response_callbacks_counter: AtomicU32::new(0), | ||
response_callbacks_queue: Arc::new(Mutex::new(HashMap::new())), | ||
}; | ||
|
||
let path = desktop_core::ipc::path("autofill"); | ||
|
||
let queue = client.response_callbacks_queue.clone(); | ||
std::thread::spawn(move || { | ||
let rt = tokio::runtime::Builder::new_current_thread() | ||
.enable_all() | ||
.build() | ||
.expect("Can't create runtime"); | ||
|
||
rt.spawn( | ||
desktop_core::ipc::client::connect(path, from_server_send, to_server_recv) | ||
.map(|r| r.map_err(|e| e.to_string())), | ||
); | ||
|
||
rt.block_on(async move { | ||
while let Some(message) = from_server_recv.recv().await { | ||
match serde_json::from_str::<SerializedMessage>(&message) { | ||
Ok(SerializedMessage::Connected) => { | ||
info!("Connected to server"); | ||
} | ||
Ok(SerializedMessage::Disconnected) => { | ||
info!("Disconnected from server"); | ||
} | ||
Ok(SerializedMessage::Message { | ||
sequence_number, | ||
value, | ||
}) => match queue.lock().unwrap().remove(&sequence_number) { | ||
Some(cb) => match value { | ||
Ok(value) => { | ||
if let Err(e) = cb.complete(value) { | ||
error!("Error deserializing message: {}", e); | ||
} | ||
} | ||
Err(e) => cb.error(e), | ||
}, | ||
None => { | ||
error!("No callback found for sequence number: {}", sequence_number) | ||
} | ||
}, | ||
Err(e) => { | ||
error!("Error deserializing message: {}", e); | ||
} | ||
}; | ||
} | ||
}); | ||
}); | ||
|
||
client | ||
} | ||
|
||
pub fn prepare_passkey_registration( | ||
&self, | ||
request: PasskeyRegistrationRequest, | ||
callback: Arc<dyn PreparePasskeyRegistrationCallback>, | ||
) { | ||
warn!("prepare_passkey_registration: {:?}", request); | ||
|
||
self.send_message(request, Box::new(callback)); | ||
} | ||
} | ||
#[derive(Serialize, Deserialize)] | ||
#[serde(tag = "command")] | ||
enum SerializedMessage { | ||
Connected, | ||
Disconnected, | ||
Message { | ||
sequence_number: u32, | ||
value: Result<serde_json::Value, BitwardenError>, | ||
}, | ||
} | ||
|
||
impl MacOSProviderClient { | ||
fn add_callback(&self, callback: Box<dyn Callback>) -> u32 { | ||
let sequence_number = self | ||
.response_callbacks_counter | ||
.fetch_add(1, std::sync::atomic::Ordering::SeqCst); | ||
|
||
self.response_callbacks_queue | ||
.lock() | ||
.unwrap() | ||
.insert(sequence_number, callback); | ||
|
||
sequence_number | ||
} | ||
|
||
fn send_message( | ||
&self, | ||
message: impl Serialize + DeserializeOwned, | ||
callback: Box<dyn Callback>, | ||
) { | ||
let sequence_number = self.add_callback(callback); | ||
|
||
let message = serde_json::to_string(&SerializedMessage::Message { | ||
sequence_number, | ||
value: Ok(serde_json::to_value(message).unwrap()), | ||
}) | ||
.expect("Can't serialize message"); | ||
|
||
if let Err(e) = self.to_server_send.blocking_send(message) { | ||
// Make sure we remove the callback from the queue if we can't send the message | ||
if let Some(cb) = self | ||
.response_callbacks_queue | ||
.lock() | ||
.unwrap() | ||
.remove(&sequence_number) | ||
{ | ||
cb.error(BitwardenError::Internal(format!( | ||
"Error sending message: {}", | ||
e | ||
))); | ||
} | ||
} | ||
} | ||
} |
41 changes: 41 additions & 0 deletions
41
apps/desktop/desktop_native/macos_provider/src/registration.rs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
use std::sync::Arc; | ||
|
||
use serde::{Deserialize, Serialize}; | ||
|
||
use crate::{BitwardenError, Callback, UserVerification}; | ||
|
||
#[derive(uniffi::Record, Debug, Serialize, Deserialize)] | ||
pub struct PasskeyRegistrationRequest { | ||
relying_party_id: String, | ||
user_name: String, | ||
user_handle: Vec<u8>, | ||
|
||
client_data_hash: Vec<u8>, | ||
user_verification: UserVerification, | ||
} | ||
|
||
#[derive(uniffi::Record, Serialize, Deserialize)] | ||
pub struct PasskeyRegistrationCredential { | ||
relying_party: String, | ||
client_data_hash: Vec<u8>, | ||
credential_id: Vec<u8>, | ||
attestation_object: Vec<u8>, | ||
} | ||
|
||
#[uniffi::export(with_foreign)] | ||
pub trait PreparePasskeyRegistrationCallback: Send + Sync { | ||
fn on_complete(&self, credential: PasskeyRegistrationCredential); | ||
fn on_error(&self, error: BitwardenError); | ||
} | ||
|
||
impl Callback for Arc<dyn PreparePasskeyRegistrationCallback> { | ||
fn complete(&self, credential: serde_json::Value) -> Result<(), serde_json::Error> { | ||
let credential = serde_json::from_value(credential)?; | ||
PreparePasskeyRegistrationCallback::on_complete(self.as_ref(), credential); | ||
Ok(()) | ||
} | ||
|
||
fn error(&self, error: BitwardenError) { | ||
PreparePasskeyRegistrationCallback::on_error(self.as_ref(), error); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
fn main() { | ||
uniffi::uniffi_bindgen_main() | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
[bindings.swift] | ||
ffi_module_name = "BitwardenMacosProviderFFI" | ||
module_name = "BitwardenMacosProvider" | ||
generate_immutable_records = true |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
BitwardenMacosProvider.swift |
Oops, something went wrong.