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:
@@ -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"
|
||||
|
||||
@@ -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'});
|
||||
});
|
||||
20
apps/desktop/desktop_native/napi/index.d.ts
vendored
20
apps/desktop/desktop_native/napi/index.d.ts
vendored
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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": "",
|
||||
|
||||
@@ -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()))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user