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))
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 /// Desktop renderer endpoint (singleton).
55 DesktopRenderer,
56 /// Desktop main-process endpoint (singleton).
57 DesktopMain,
58}
59
60/// Describes the source of an incoming IPC message with per-variant metadata.
61///
62/// `Source` mirrors [`Endpoint`] but carries additional context about the sender
63/// that the application layer needs for security decisions (e.g., checking `origin`
64/// for web sources). Use [`From<Source> for Endpoint`] to convert a source into an
65/// addressable endpoint (dropping the metadata).
66#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, Hash)]
67#[cfg_attr(feature = "wasm", derive(Tsify), tsify(into_wasm_abi, from_wasm_abi))]
68pub enum Source {
69 /// A web source identified by tab ID and document ID, with the origin of the sending page.
70 Web {
71 /// Chrome tab ID used for routing messages back to this tab.
72 tab_id: i32,
73 /// Document ID (`sender.documentId`) identifying the specific document instance.
74 document_id: String,
75 /// The origin of the web page (e.g., `"https://vault.bitwarden.com"`).
76 origin: String,
77 },
78 /// Browser foreground source (popup, sidebar, or extension page).
79 BrowserForeground {
80 /// Transport-assigned identifier for the browser foreground instance.
81 id: i32,
82 },
83 /// Browser background source (service worker/background context).
84 BrowserBackground {
85 /// Host identifier for this endpoint.
86 id: HostId,
87 },
88 /// Desktop renderer source (singleton).
89 DesktopRenderer,
90 /// Desktop main-process source (singleton).
91 DesktopMain,
92}
93
94impl Source {
95 /// Convert this source into its corresponding [`Endpoint`], dropping any
96 /// source-specific metadata (such as `origin`).
97 pub fn to_endpoint(&self) -> Endpoint {
98 Endpoint::from(self.clone())
99 }
100}
101
102impl From<Source> for Endpoint {
103 fn from(source: Source) -> Self {
104 match source {
105 Source::Web {
106 tab_id,
107 document_id,
108 ..
109 } => Endpoint::Web {
110 tab_id,
111 document_id,
112 },
113 Source::BrowserForeground { id } => Endpoint::BrowserForeground { id },
114 Source::BrowserBackground { id } => Endpoint::BrowserBackground { id },
115 Source::DesktopRenderer => Endpoint::DesktopRenderer,
116 Source::DesktopMain => Endpoint::DesktopMain,
117 }
118 }
119}