1
0
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:
Oscar Hinton
2023-10-02 18:50:57 +02:00
committed by GitHub
parent 6aed74d241
commit 30feb60645
14 changed files with 485 additions and 240 deletions

View File

@@ -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]

View 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());
}
}

View File

@@ -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()))
}
}

View File

@@ -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) };