1
0
mirror of https://github.com/bitwarden/browser synced 2026-01-05 10:03:21 +00:00

[PM-7846] Implement a rust based native messaging proxy and IPC system

This commit is contained in:
Daniel García
2024-06-20 18:11:24 +02:00
parent d92e1b3eca
commit 0a83b8ddaf
26 changed files with 961 additions and 358 deletions

View File

@@ -16,8 +16,10 @@ manual_test = []
[dependencies]
anyhow = "=1.0.86"
desktop_core = { path = "../core" }
napi = { version = "=2.16.6", features = ["async"] }
napi-derive = "=2.16.5"
napi = { version = "=2.16.7", features = ["async"] }
napi-derive = "=2.16.6"
tokio = { version = "1.38.0" }
tokio-util = "0.7.11"
[build-dependencies]
napi-build = "=2.1.3"

View File

@@ -1,24 +0,0 @@
/* eslint-disable @typescript-eslint/no-var-requires */
const child_process = require("child_process");
const process = require("process");
let targets = [];
switch (process.platform) {
case "win32":
targets = ["i686-pc-windows-msvc", "x86_64-pc-windows-msvc", "aarch64-pc-windows-msvc"];
break;
case "darwin":
targets = ["x86_64-apple-darwin", "aarch64-apple-darwin"];
break;
default:
targets = ['x86_64-unknown-linux-musl'];
process.env["PKG_CONFIG_ALLOW_CROSS"] = "1";
process.env["PKG_CONFIG_ALL_STATIC"] = "1";
break;
}
targets.forEach(target => {
child_process.execSync(`npm run build -- --target ${target}`, {stdio: 'inherit'});
});

View File

@@ -41,3 +41,23 @@ export namespace clipboards {
export function read(): Promise<string>
export function write(text: string, password: boolean): Promise<void>
}
export namespace ipc {
export const enum IpcMessageType {
Connected = 0,
Disconnected = 1,
Message = 2
}
export class IpcMessage {
clientId: number
kind: IpcMessageType
message: string
}
export class IpcServer {
/** Create and start the IPC server. */
static listen(name: string, callback: (error: null | Error, message: IpcMessage) => void): IpcServer
/** Stop the IPC server. */
stop(): void
/** Send a message over the IPC server. */
send(message: string): void
}
}

View File

@@ -206,8 +206,9 @@ if (!nativeBinding) {
throw new Error(`Failed to load native binding`)
}
const { passwords, biometrics, clipboards } = nativeBinding
const { passwords, biometrics, clipboards, ipc } = nativeBinding
module.exports.passwords = passwords
module.exports.biometrics = biometrics
module.exports.clipboards = clipboards
module.exports.ipc = ipc

View File

@@ -5,7 +5,6 @@
"scripts": {
"build": "napi build --release --platform --js false",
"build:debug": "napi build --platform --js false",
"build:cross-platform": "node build.js",
"test": "cargo test"
},
"author": "",

View File

@@ -142,3 +142,89 @@ pub mod clipboards {
.map_err(|e| napi::Error::from_reason(e.to_string()))
}
}
#[napi]
pub mod ipc {
use desktop_core::ipc::server::{Message, MessageType};
use napi::threadsafe_function::{
ErrorStrategy, ThreadsafeFunction, ThreadsafeFunctionCallMode,
};
use tokio_util::sync::PollSender;
#[napi]
pub struct IpcMessage {
pub client_id: u32,
pub kind: IpcMessageType,
pub message: String,
}
impl From<Message> for IpcMessage {
fn from(message: Message) -> Self {
IpcMessage {
client_id: message.client_id,
kind: message.kind.into(),
message: message.message,
}
}
}
#[napi]
pub enum IpcMessageType {
Connected,
Disconnected,
Message,
}
impl From<MessageType> for IpcMessageType {
fn from(message_type: MessageType) -> Self {
match message_type {
MessageType::Connected => IpcMessageType::Connected,
MessageType::Disconnected => IpcMessageType::Disconnected,
MessageType::Message => IpcMessageType::Message,
}
}
}
#[napi]
pub struct IpcServer {
server: desktop_core::ipc::server::Server,
}
#[napi]
impl IpcServer {
/// Create and start the IPC server.
#[napi(factory)]
pub fn listen(
name: String,
#[napi(ts_arg_type = "(error: null | Error, message: IpcMessage) => void")]
callback: ThreadsafeFunction<IpcMessage, ErrorStrategy::CalleeHandled>,
) -> napi::Result<Self> {
let (tx, mut rx) = tokio::sync::mpsc::channel::<Message>(32);
tokio::spawn(async move {
while let Some(message) = rx.recv().await {
callback.call(Ok(message.into()), ThreadsafeFunctionCallMode::NonBlocking);
}
});
let server = desktop_core::ipc::server::Server::start(&name, PollSender::new(tx))
.map_err(|e| napi::Error::from_reason(e.to_string()))?;
Ok(IpcServer { server })
}
/// Stop the IPC server.
#[napi]
pub fn stop(&self) -> napi::Result<()> {
self.server.stop();
Ok(())
}
/// Send a message over the IPC server.
#[napi]
pub fn send(&self, message: String) -> napi::Result<()> {
self.server
.send(message)
.map_err(|e| napi::Error::from_reason(e.to_string()))
}
}
}