1use crate::{Token, util};
2use sonic_rs::Value;
3
4#[derive(Debug, serde::Serialize)]
6pub struct SocketAuth {
7 pub auth: String,
8 #[serde(skip_serializing_if = "Option::is_none")]
9 pub channel_data: Option<String>,
10 #[serde(skip_serializing_if = "Option::is_none")]
11 pub shared_secret: Option<String>,
12}
13
14#[derive(Debug, serde::Serialize)]
16pub struct UserAuth {
17 pub auth: String,
18 pub user_data: String,
19}
20
21pub fn get_socket_signature(
23 sockudo: &crate::Sockudo,
24 token: &Token,
25 channel: &str,
26 socket_id: &str,
27 data: Option<&Value>,
28) -> crate::Result<SocketAuth> {
29 #[cfg(not(feature = "encryption"))]
30 let _ = sockudo;
31 let mut signature_data = vec![socket_id.to_string(), channel.to_string()];
32 let mut channel_data = None;
33
34 if let Some(data) = data {
35 let serialized = sonic_rs::to_string(data)?;
36 signature_data.push(serialized.clone());
37 channel_data = Some(serialized);
38 }
39
40 let auth_string = signature_data.join(":");
41 let signature = token.sign(&auth_string);
42 let auth = format!("{}:{}", token.key, signature);
43
44 #[cfg_attr(not(feature = "encryption"), allow(unused_mut))]
45 let mut result = SocketAuth {
46 auth,
47 channel_data,
48 shared_secret: None,
49 };
50
51 if util::is_encrypted_channel(channel) {
53 #[cfg(feature = "encryption")]
54 {
55 if sockudo.config().encryption_master_key().is_none() {
56 return Err(crate::SockudoError::Encryption {
57 message: "Cannot generate shared_secret because encryptionMasterKey is not set"
58 .to_string(),
59 });
60 }
61
62 let shared_secret = sockudo.channel_shared_secret(channel)?;
63 result.shared_secret = Some(base64::Engine::encode(
64 &base64::engine::general_purpose::STANDARD,
65 shared_secret,
66 ));
67 }
68
69 #[cfg(not(feature = "encryption"))]
70 {
71 return Err(crate::SockudoError::Encryption {
72 message: "Encryption support is not enabled. Enable the 'encryption' feature to use encrypted channels.".to_string(),
73 });
74 }
75 }
76
77 Ok(result)
78}
79
80pub fn get_socket_signature_for_user(
82 token: &Token,
83 socket_id: &str,
84 user_data: &Value,
85) -> crate::Result<UserAuth> {
86 let serialized_user_data = sonic_rs::to_string(user_data)?;
87 let signature_string = format!("{}::user::{}", socket_id, serialized_user_data);
88 let signature = token.sign(&signature_string);
89
90 Ok(UserAuth {
91 auth: format!("{}:{}", token.key, signature),
92 user_data: serialized_user_data,
93 })
94}
95
96#[cfg(test)]
97mod tests {
98 use super::*;
99 use sonic_rs::json;
100
101 #[test]
102 fn test_get_socket_signature_for_user() {
103 let token = Token::new("test_key", "test_secret");
104 let user_data = json!({"id": "123", "name": "Test User"});
105
106 let result = get_socket_signature_for_user(&token, "123.456", &user_data).unwrap();
107
108 assert!(result.auth.starts_with("test_key:"));
109 assert!(result.user_data.contains("123"));
110 }
111
112 #[cfg(feature = "encryption")]
113 #[test]
114 fn test_encrypted_channel_auth_with_encryption() {
115 use crate::{Config, Sockudo};
116
117 let config = Config::builder()
119 .app_id("test")
120 .key("test_key")
121 .secret("test_secret")
122 .encryption_master_key_base64("MDEyMzQ1Njc4OWFiY2RlZjAxMjM0NTY3ODlhYmNkZWY=")
123 .unwrap()
124 .build()
125 .unwrap();
126
127 let sockudo = Sockudo::new(config).unwrap();
128 let token = Token::new("test_key", "test_secret");
129
130 let result =
131 get_socket_signature(&sockudo, &token, "private-encrypted-test", "123.456", None)
132 .unwrap();
133
134 assert!(result.shared_secret.is_some());
135 }
136
137 #[cfg(not(feature = "encryption"))]
138 #[test]
139 fn test_encrypted_channel_auth_without_encryption() {
140 use crate::{Config, Sockudo};
141
142 let config = Config::builder()
144 .app_id("test")
145 .key("test_key")
146 .secret("test_secret")
147 .build()
148 .unwrap();
149
150 let sockudo = Sockudo::new(config).unwrap();
151 let token = Token::new("test_key", "test_secret");
152
153 let result =
154 get_socket_signature(&sockudo, &token, "private-encrypted-test", "123.456", None);
155
156 assert!(result.is_err());
158 if let Err(crate::SockudoError::Encryption { message }) = result {
159 assert!(message.contains("Encryption support is not enabled"));
160 } else {
161 panic!("Expected encryption error");
162 }
163 }
164}