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