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))
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}