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)]
23pub struct IpcEnvelope {
24 pub token: String,
25 #[serde(default, skip_serializing_if = "Option::is_none")]
26 pub client_token: Option<String>,
27 #[serde(default, skip_serializing_if = "Option::is_none")]
28 pub origin: Option<Origin>,
29 pub message: IpcMessage,
30}
31
32impl IpcEnvelope {
33 pub fn new(token: String, message: IpcMessage) -> Self {
34 Self {
35 token,
36 client_token: None,
37 origin: None,
38 message,
39 }
40 }
41
42 pub fn with_client_token(mut self, client_token: Option<String>) -> Self {
43 self.client_token = client_token;
44 self
45 }
46
47 pub fn with_origin(mut self, origin: Origin) -> Self {
48 self.origin = Some(origin);
49 self
50 }
51}
52
53#[cfg(test)]
54mod tests {
55 use super::*;
56
57 #[test]
58 fn test_ipc_envelope_serialization() {
59 let envelope = IpcEnvelope {
60 token: "test_token_12345".to_string(),
61 client_token: None,
62 origin: None,
63 message: IpcMessage::GetCredential {
64 domain: "example.com".to_string(),
65 },
66 };
67
68 let serialized = serde_json::to_string(&envelope).unwrap();
69 let deserialized: IpcEnvelope = serde_json::from_str(&serialized).unwrap();
70
71 assert_eq!(deserialized.token, envelope.token);
72 assert!(deserialized.client_token.is_none());
73 assert!(deserialized.origin.is_none());
74 match deserialized.message {
75 IpcMessage::GetCredential { domain } => {
76 assert_eq!(domain, "example.com");
77 }
78 _ => panic!("Wrong message type"),
79 }
80 }
81
82 #[test]
83 fn legacy_envelope_without_new_fields_parses() {
84 let legacy = r#"{"token":"tok","message":"CheckVault"}"#;
86 let parsed: IpcEnvelope = serde_json::from_str(legacy).unwrap();
87 assert_eq!(parsed.token, "tok");
88 assert!(parsed.client_token.is_none());
89 assert!(parsed.origin.is_none());
90 }
91
92 #[test]
93 fn envelope_with_origin_and_client_token_round_trips() {
94 let envelope = IpcEnvelope::new("tok".to_string(), IpcMessage::CheckVault)
95 .with_client_token(Some("spt_abc".to_string()))
96 .with_origin(Origin::NativeHost);
97
98 let serialized = serde_json::to_string(&envelope).unwrap();
99 assert!(serialized.contains("\"origin\":\"native_host\""));
100 let parsed: IpcEnvelope = serde_json::from_str(&serialized).unwrap();
101 assert_eq!(parsed.origin, Some(Origin::NativeHost));
102 assert_eq!(parsed.client_token.as_deref(), Some("spt_abc"));
103 }
104}