-
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
45c9202
commit e2b3738
Showing
24 changed files
with
1,604 additions
and
27 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"] | ||
members = ["napi", "core", "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
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,99 @@ | ||
use std::{ | ||
path::{Path, PathBuf}, | ||
time::Duration, | ||
}; | ||
|
||
use interprocess::local_socket::{ | ||
tokio::{prelude::*, Stream}, | ||
GenericFilePath, ToFsName, | ||
}; | ||
use log::{error, info}; | ||
use tokio::{ | ||
io::{AsyncReadExt, AsyncWriteExt}, | ||
time::sleep, | ||
}; | ||
|
||
use crate::ipc::NATIVE_MESSAGING_BUFFER_SIZE; | ||
|
||
pub async fn connect( | ||
path: PathBuf, | ||
send: tokio::sync::mpsc::Sender<String>, | ||
mut recv: tokio::sync::mpsc::Receiver<String>, | ||
) { | ||
// Keep track of connection failures to make sure we don't leave the process as a zombie | ||
let mut connection_failures = 0; | ||
|
||
loop { | ||
match connect_inner(&path, &send, &mut recv).await { | ||
Ok(()) => return, | ||
Err(e) => { | ||
connection_failures += 1; | ||
if connection_failures >= 20 { | ||
error!("Failed to connect to IPC server after 20 attempts: {e}"); | ||
return; | ||
} | ||
|
||
error!("Failed to connect to IPC server: {e}"); | ||
} | ||
} | ||
|
||
sleep(Duration::from_secs(5)).await; | ||
} | ||
} | ||
|
||
async fn connect_inner( | ||
path: &Path, | ||
send: &tokio::sync::mpsc::Sender<String>, | ||
recv: &mut tokio::sync::mpsc::Receiver<String>, | ||
) -> Result<(), Box<dyn std::error::Error>> { | ||
info!("Attempting to connect to {}", path.display()); | ||
|
||
let name = path.as_os_str().to_fs_name::<GenericFilePath>()?; | ||
let mut conn = Stream::connect(name).await?; | ||
|
||
info!("Connected to {}", path.display()); | ||
|
||
send.send("{\"command\":\"connected\"}".to_owned()).await?; | ||
|
||
let mut buffer = vec![0; NATIVE_MESSAGING_BUFFER_SIZE]; | ||
|
||
// Listen to IPC messages | ||
loop { | ||
tokio::select! { | ||
// Forward messages to the IPC server | ||
msg = recv.recv() => { | ||
match msg { | ||
Some(msg) => { | ||
conn.write_all(msg.as_bytes()).await?; | ||
} | ||
None => { | ||
info!("Client channel closed"); | ||
break; | ||
}, | ||
} | ||
}, | ||
|
||
// Forward messages from the IPC server | ||
res = conn.read(&mut buffer[..]) => { | ||
match res { | ||
Err(e) => { | ||
error!("Error reading from IPC server: {e}"); | ||
send.send("{\"command\":\"disconnected\"}".to_owned()).await?; | ||
break; | ||
} | ||
Ok(0) => { | ||
info!("Connection closed"); | ||
send.send("{\"command\":\"disconnected\"}".to_owned()).await?; | ||
break; | ||
} | ||
Ok(n) => { | ||
let message = String::from_utf8_lossy(&buffer[..n]).to_string(); | ||
send.send(message).await?; | ||
} | ||
} | ||
} | ||
} | ||
} | ||
|
||
Ok(()) | ||
} |
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,60 @@ | ||
pub mod client; | ||
pub mod server; | ||
|
||
/// The maximum size of a message that can be sent over IPC. | ||
/// According to the documentation, the maximum size sent to the browser is 1MB. | ||
/// While the maximum size sent from the browser to the native messaging host is 4GB. | ||
/// | ||
/// Currently we are setting the maximum both ways to be 1MB. | ||
/// | ||
/// https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/Native_messaging#app_side | ||
/// https://developer.chrome.com/docs/extensions/develop/concepts/native-messaging#native-messaging-host-protocol | ||
pub const NATIVE_MESSAGING_BUFFER_SIZE: usize = 1024 * 1024; | ||
|
||
|
||
/// Resolve the path to the IPC socket. | ||
pub fn path(name: &str) -> std::path::PathBuf { | ||
#[cfg(target_os = "windows")] | ||
{ | ||
// Use a unique IPC pipe //./pipe/xxxxxxxxxxxxxxxxx.app.bitwarden per user. | ||
// Hashing prevents problems with reserved characters and file length limitations. | ||
use base64::{engine::general_purpose::URL_SAFE_NO_PAD, Engine}; | ||
use sha2::Digest; | ||
let home = dirs::home_dir().unwrap(); | ||
let hash = sha2::Sha256::digest(home.as_os_str().as_encoded_bytes()); | ||
let hash_b64 = URL_SAFE_NO_PAD.encode(hash.as_slice()); | ||
|
||
format!(r"\\.\pipe\{hash_b64}.app.{name}").into() | ||
} | ||
|
||
#[cfg(target_os = "macos")] | ||
{ | ||
let mut home = dirs::home_dir().unwrap(); | ||
|
||
// When running in an unsandboxed environment, path is: /Users/<user>/ | ||
// While running sandboxed, it's different: /Users/<user>/Library/Containers/com.bitwarden.desktop/Data | ||
// | ||
// We want to use App Groups in /Users/<user>/Library/Group Containers/LTZ2PFU5D6.com.bitwarden.desktop, | ||
// so we need to remove all the components after the user. | ||
// Note that we subtract 3 because the root directory is counted as a component (/, Users, <user>). | ||
let num_components = home.components().count(); | ||
for _ in 0..num_components - 3 { | ||
home.pop(); | ||
} | ||
|
||
home.join(format!( | ||
"Library/Group Containers/LTZ2PFU5D6.com.bitwarden.desktop/tmp/app.{name}" | ||
)) | ||
} | ||
|
||
#[cfg(target_os = "linux")] | ||
{ | ||
// On Linux, we use the user's cache directory. | ||
let home = dirs::cache_dir().unwrap(); | ||
let path_dir = home.join("com.bitwarden.desktop"); | ||
|
||
// The chache directory might not exist, so create it | ||
let _ = std::fs::create_dir_all(&path_dir); | ||
path_dir.join(format!("app.{name}")) | ||
} | ||
} |
Oops, something went wrong.