sentinelpass_protocol/
envelope.rs1use crate::message::IpcMessage;
4use serde::{Deserialize, Serialize};
5
6#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
10#[serde(rename_all = "snake_case")]
11pub enum Origin {
12 NativeHost,
14 Cli,
16}
17
18#[derive(Debug, Clone, Serialize, Deserialize)]
27pub struct IpcEnvelope {
28 pub token: String,
29 #[serde(default, skip_serializing_if = "Option::is_none")]
30 pub client_token: Option<String>,
31 #[serde(default, skip_serializing_if = "Option::is_none")]
32 pub origin: Option<Origin>,
33 #[serde(default, skip_serializing_if = "Option::is_none")]
34 pub capability: Option<String>,
35 pub message: IpcMessage,
36}
37
38impl IpcEnvelope {
39 pub fn new(token: String, message: IpcMessage) -> Self {
40 Self {
41 token,
42 client_token: None,
43 origin: None,
44 capability: None,
45 message,
46 }
47 }
48
49 pub fn with_client_token(mut self, client_token: Option<String>) -> Self {
50 self.client_token = client_token;
51 self
52 }
53
54 pub fn with_origin(mut self, origin: Origin) -> Self {
55 self.origin = Some(origin);
56 self
57 }
58
59 pub fn with_capability(mut self, capability: Option<String>) -> Self {
60 self.capability = capability;
61 self
62 }
63}
64
65#[cfg(test)]
66mod tests {
67 use super::*;
68
69 #[test]
70 fn test_ipc_envelope_serialization() {
71 let envelope = IpcEnvelope {
72 token: "test_token_12345".to_string(),
73 client_token: None,
74 origin: None,
75 capability: None,
76 message: IpcMessage::GetCredential {
77 domain: "example.com".to_string(),
78 page_url: None,
79 username: None,
80 },
81 };
82
83 let serialized = serde_json::to_string(&envelope).unwrap();
84 let deserialized: IpcEnvelope = serde_json::from_str(&serialized).unwrap();
85
86 assert_eq!(deserialized.token, envelope.token);
87 assert!(deserialized.client_token.is_none());
88 assert!(deserialized.origin.is_none());
89 match deserialized.message {
90 IpcMessage::GetCredential { domain, .. } => {
91 assert_eq!(domain, "example.com");
92 }
93 _ => panic!("Wrong message type"),
94 }
95 }
96
97 #[test]
98 fn legacy_envelope_without_new_fields_parses() {
99 let legacy = r#"{"token":"tok","message":"CheckVault"}"#;
101 let parsed: IpcEnvelope = serde_json::from_str(legacy).unwrap();
102 assert_eq!(parsed.token, "tok");
103 assert!(parsed.client_token.is_none());
104 assert!(parsed.origin.is_none());
105 }
106
107 #[test]
108 fn envelope_with_origin_and_client_token_round_trips() {
109 let envelope = IpcEnvelope::new("tok".to_string(), IpcMessage::CheckVault)
110 .with_client_token(Some("spt_abc".to_string()))
111 .with_origin(Origin::NativeHost);
112
113 let serialized = serde_json::to_string(&envelope).unwrap();
114 assert!(serialized.contains("\"origin\":\"native_host\""));
115 let parsed: IpcEnvelope = serde_json::from_str(&serialized).unwrap();
116 assert_eq!(parsed.origin, Some(Origin::NativeHost));
117 assert_eq!(parsed.client_token.as_deref(), Some("spt_abc"));
118 }
119}