Skip to main content

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}