mirror of
https://github.com/bitwarden/browser
synced 2025-12-20 10:13:31 +00:00
[BEEEP] [PM-565] Implement clipboard logic in rust (#4516)
Implement the Desktop clipboard logic natively using rust. This uses the arboard crate for clipboard functionality. This change consists of 3 portions: * Rust component. * Updating renderer to call main using electron ipc. * Update main to listen to renderer ipc and forward calls to the native clipboard module.
This commit is contained in:
@@ -7,8 +7,8 @@ use rand::RngCore;
|
||||
use retry::delay::Fixed;
|
||||
use sha2::{Digest, Sha256};
|
||||
use windows::{
|
||||
h,
|
||||
core::{factory, HSTRING},
|
||||
h,
|
||||
Foundation::IAsyncOperation,
|
||||
Security::{
|
||||
Credentials::{
|
||||
@@ -241,7 +241,9 @@ fn set_focus(window: HWND) {
|
||||
impl KeyMaterial {
|
||||
fn digest_material(&self) -> String {
|
||||
match self.client_key_part_b64.as_deref() {
|
||||
Some(client_key_part_b64) => format!("{}|{}", self.os_key_part_b64, client_key_part_b64),
|
||||
Some(client_key_part_b64) => {
|
||||
format!("{}|{}", self.os_key_part_b64, client_key_part_b64)
|
||||
}
|
||||
None => self.os_key_part_b64.clone(),
|
||||
}
|
||||
}
|
||||
@@ -419,7 +421,14 @@ mod tests {
|
||||
let mut key_material = key_material();
|
||||
key_material.client_key_part_b64 = None;
|
||||
let result = key_material.derive_key().unwrap();
|
||||
assert_eq!(result, [81, 100, 62, 172, 151, 119, 182, 58, 123, 38, 129, 116, 209, 253, 66, 118, 218, 237, 236, 155, 201, 234, 11, 198, 229, 171, 246, 144, 71, 188, 84, 246].into());
|
||||
assert_eq!(
|
||||
result,
|
||||
[
|
||||
81, 100, 62, 172, 151, 119, 182, 58, 123, 38, 129, 116, 209, 253, 66, 118, 218,
|
||||
237, 236, 155, 201, 234, 11, 198, 229, 171, 246, 144, 71, 188, 84, 246
|
||||
]
|
||||
.into()
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
56
apps/desktop/desktop_native/src/clipboard.rs
Normal file
56
apps/desktop/desktop_native/src/clipboard.rs
Normal file
@@ -0,0 +1,56 @@
|
||||
use anyhow::Result;
|
||||
use arboard::{Clipboard, Set};
|
||||
|
||||
pub fn read() -> Result<String> {
|
||||
let mut clipboard = Clipboard::new()?;
|
||||
|
||||
Ok(clipboard.get_text()?)
|
||||
}
|
||||
|
||||
pub fn write(text: &str, password: bool) -> Result<()> {
|
||||
let mut clipboard = Clipboard::new()?;
|
||||
|
||||
let set = clipboard_set(clipboard.set(), password);
|
||||
|
||||
set.text(text)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// Exclude from windows clipboard history
|
||||
#[cfg(target_os = "windows")]
|
||||
fn clipboard_set(set: Set, password: bool) -> Set {
|
||||
use arboard::SetExtWindows;
|
||||
|
||||
if password {
|
||||
set.exclude_from_cloud().exclude_from_history()
|
||||
} else {
|
||||
set
|
||||
}
|
||||
}
|
||||
|
||||
// Wait for clipboard to be available on linux
|
||||
#[cfg(target_os = "linux")]
|
||||
fn clipboard_set(set: Set, _password: bool) -> Set {
|
||||
use arboard::SetExtLinux;
|
||||
|
||||
set.wait()
|
||||
}
|
||||
|
||||
#[cfg(target_os = "macos")]
|
||||
fn clipboard_set(set: Set, _password: bool) -> Set {
|
||||
set
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "manual_test", not(target_os = "linux")))]
|
||||
fn test_write_read() {
|
||||
let message = "Hello world!";
|
||||
|
||||
write(message, false).unwrap();
|
||||
assert_eq!(message, read().unwrap());
|
||||
}
|
||||
}
|
||||
@@ -2,6 +2,7 @@
|
||||
extern crate napi_derive;
|
||||
|
||||
mod biometric;
|
||||
mod clipboard;
|
||||
mod crypto;
|
||||
mod error;
|
||||
mod password;
|
||||
@@ -107,3 +108,17 @@ pub mod biometrics {
|
||||
pub iv_b64: String,
|
||||
}
|
||||
}
|
||||
|
||||
#[napi]
|
||||
pub mod clipboards {
|
||||
#[napi]
|
||||
pub async fn read() -> napi::Result<String> {
|
||||
super::clipboard::read().map_err(|e| napi::Error::from_reason(e.to_string()))
|
||||
}
|
||||
|
||||
#[napi]
|
||||
pub async fn write(text: String, password: bool) -> napi::Result<()> {
|
||||
super::clipboard::write(&text, password)
|
||||
.map_err(|e| napi::Error::from_reason(e.to_string()))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -95,7 +95,7 @@ pub fn set_password(service: &str, account: &str, password: &str) -> Result<()>
|
||||
let credential = CREDENTIALW {
|
||||
Flags: CRED_FLAGS(CRED_FLAGS_NONE),
|
||||
Type: CRED_TYPE_GENERIC,
|
||||
TargetName: PWSTR(unsafe { target_name.as_mut_ptr() }),
|
||||
TargetName: PWSTR(target_name.as_mut_ptr()),
|
||||
Comment: PWSTR::null(),
|
||||
LastWritten: last_written,
|
||||
CredentialBlobSize: credential_len,
|
||||
@@ -104,7 +104,7 @@ pub fn set_password(service: &str, account: &str, password: &str) -> Result<()>
|
||||
AttributeCount: 0,
|
||||
Attributes: std::ptr::null_mut(),
|
||||
TargetAlias: PWSTR::null(),
|
||||
UserName: PWSTR(unsafe { user_name.as_mut_ptr() }),
|
||||
UserName: PWSTR(user_name.as_mut_ptr()),
|
||||
};
|
||||
|
||||
let result = unsafe { CredWriteW(&credential, 0) };
|
||||
|
||||
Reference in New Issue
Block a user