bitwarden_ipc/endpoint.rs
1use serde::{Deserialize, Serialize};
2#[cfg(feature = "wasm")]
3use {tsify::Tsify, wasm_bindgen::prelude::*};
4
5/// Identifies a host endpoint, one that manages connections for other endpoints.
6///
7/// Host endpoints can be addressed relationally (when the sender has a direct connection
8/// and there is only one from their perspective) or by a specific transport-assigned ID
9/// (when distinguishing between multiple instances).
10#[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq, Hash)]
11#[cfg_attr(feature = "wasm", derive(Tsify), tsify(into_wasm_abi, from_wasm_abi))]
12pub enum HostId {
13 /// The sender's own instance of this endpoint type. Used when there is exactly one
14 /// from the sender's perspective (e.g., a web tab addressing its browser background).
15 Own,
16 /// A specific instance identified by a transport-assigned numeric value
17 /// (e.g., native messaging client ID).
18 Id(i32),
19}
20
21/// IPC destination/source endpoint for SDK clients.
22///
23/// Endpoints are categorized by their role in the connection topology:
24/// - **Host endpoints** ([`HostId`]): Connection hubs that can be addressed relationally or
25/// specifically. ([`BrowserBackground`](Endpoint::BrowserBackground), [`Cli`](Endpoint::Cli))
26/// - **Leaf endpoints**: Addressed by transport-assigned IDs. ([`Web`](Endpoint::Web),
27/// [`BrowserForeground`](Endpoint::BrowserForeground))
28/// - **Singleton endpoints**: Exactly one instance globally, no ID needed.
29/// ([`DesktopMain`](Endpoint::DesktopMain), [`DesktopRenderer`](Endpoint::DesktopRenderer))
30#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, Hash)]
31#[cfg_attr(feature = "wasm", derive(Tsify), tsify(into_wasm_abi, from_wasm_abi))]
32pub enum Endpoint {
33 /// A web endpoint identified by a Chrome tab ID (for routing via
34 /// `chrome.tabs.sendMessage`) and a document ID (for identity validation).
35 /// The document ID invalidates on navigation, allowing the browser background
36 /// to reject delivery if the page changed since the message was addressed.
37 Web {
38 /// Chrome tab ID used for routing messages to the correct tab.
39 tab_id: i32,
40 /// Document ID (`sender.documentId`) identifying a specific document instance.
41 document_id: String,
42 },
43 /// Browser foreground endpoint (popup, sidebar, or extension page) identified by a
44 /// transport-assigned numeric ID.
45 BrowserForeground {
46 /// Transport-assigned identifier for a browser foreground instance.
47 id: i32,
48 },
49 /// Browser background endpoint (service worker/background context).
50 BrowserBackground {
51 /// Host identifier for addressing this endpoint.
52 id: HostId,
53 },
54 /// CLI endpoint. Each CLI invocation is its own process, so instances are
55 /// distinguished by a host identifier.
56 Cli {
57 /// Host identifier for addressing this endpoint.
58 id: HostId,
59 },
60 /// Desktop renderer endpoint (singleton).
61 DesktopRenderer,
62 /// Desktop main-process endpoint (singleton).
63 DesktopMain,
64}
65
66/// Describes the source of an incoming IPC message with per-variant metadata.
67///
68/// `Source` mirrors [`Endpoint`] but carries additional context about the sender
69/// that the application layer needs for security decisions (e.g., checking `origin`
70/// for web sources). Use [`From<Source> for Endpoint`] to convert a source into an
71/// addressable endpoint (dropping the metadata).
72#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, Hash)]
73#[cfg_attr(feature = "wasm", derive(Tsify), tsify(into_wasm_abi, from_wasm_abi))]
74pub enum Source {
75 /// A web source identified by tab ID and document ID, with the origin of the sending page.
76 Web {
77 /// Chrome tab ID used for routing messages back to this tab.
78 tab_id: i32,
79 /// Document ID (`sender.documentId`) identifying the specific document instance.
80 document_id: String,
81 /// The origin of the web page (e.g., `"https://vault.bitwarden.com"`).
82 origin: String,
83 },
84 /// Browser foreground source (popup, sidebar, or extension page).
85 BrowserForeground {
86 /// Transport-assigned identifier for the browser foreground instance.
87 id: i32,
88 },
89 /// Browser background source (service worker/background context).
90 BrowserBackground {
91 /// Host identifier for this endpoint.
92 id: HostId,
93 },
94 /// CLI source, identified by a host identifier.
95 Cli {
96 /// Host identifier for this endpoint.
97 id: HostId,
98 },
99 /// Desktop renderer source (singleton).
100 DesktopRenderer,
101 /// Desktop main-process source (singleton).
102 DesktopMain,
103}
104
105impl Source {
106 /// Convert this source into its corresponding [`Endpoint`], dropping any
107 /// source-specific metadata (such as `origin`).
108 pub fn to_endpoint(&self) -> Endpoint {
109 Endpoint::from(self.clone())
110 }
111}
112
113impl From<Source> for Endpoint {
114 fn from(source: Source) -> Self {
115 match source {
116 Source::Web {
117 tab_id,
118 document_id,
119 ..
120 } => Endpoint::Web {
121 tab_id,
122 document_id,
123 },
124 Source::BrowserForeground { id } => Endpoint::BrowserForeground { id },
125 Source::BrowserBackground { id } => Endpoint::BrowserBackground { id },
126 Source::Cli { id } => Endpoint::Cli { id },
127 Source::DesktopRenderer => Endpoint::DesktopRenderer,
128 Source::DesktopMain => Endpoint::DesktopMain,
129 }
130 }
131}