unifly_api/controller/session_queries/
settings.rs1use crate::controller::Controller;
2use crate::controller::support::require_session;
3use crate::core_error::CoreError;
4use crate::model::VpnSetting;
5
6use super::common::redact_sensitive_value;
7
8const VPN_SETTING_KEYS: &[&str] = &[
9 "teleport",
10 "magic_site_to_site_vpn",
11 "openvpn",
12 "peer_to_peer",
13];
14
15impl Controller {
16 pub async fn list_vpn_settings(&self) -> Result<Vec<VpnSetting>, CoreError> {
17 let guard = self.inner.session_client.lock().await;
18 let session = require_session(guard.as_ref())?;
19 let raw = session.get_site_settings().await?;
20 let mut settings = raw
21 .iter()
22 .filter_map(vpn_setting_from_raw)
23 .collect::<Vec<_>>();
24 settings.sort_by(|left, right| left.key.cmp(&right.key));
25 Ok(settings)
26 }
27
28 pub async fn get_vpn_setting(&self, key: &str) -> Result<VpnSetting, CoreError> {
29 self.list_vpn_settings()
30 .await?
31 .into_iter()
32 .find(|setting| setting.key == key)
33 .ok_or_else(|| CoreError::NotFound {
34 entity_type: "vpn setting".into(),
35 identifier: key.into(),
36 })
37 }
38
39 pub async fn update_vpn_setting(
40 &self,
41 key: &str,
42 body: &serde_json::Value,
43 ) -> Result<VpnSetting, CoreError> {
44 if !VPN_SETTING_KEYS.contains(&key) {
45 return Err(CoreError::NotFound {
46 entity_type: "vpn setting".into(),
47 identifier: key.into(),
48 });
49 }
50
51 let guard = self.inner.session_client.lock().await;
52 let session = require_session(guard.as_ref())?;
53 session.set_site_setting(key, body).await?;
54 drop(guard);
55
56 self.get_vpn_setting(key).await
57 }
58
59 pub async fn get_all_site_settings(&self) -> Result<Vec<serde_json::Value>, CoreError> {
60 let guard = self.inner.session_client.lock().await;
61 let session = require_session(guard.as_ref())?;
62 Ok(session.get_site_settings().await?)
63 }
64
65 pub async fn get_site_setting(&self, key: &str) -> Result<serde_json::Value, CoreError> {
66 self.get_all_site_settings()
67 .await?
68 .into_iter()
69 .find(|s| s.get("key").and_then(|v| v.as_str()) == Some(key))
70 .ok_or_else(|| CoreError::NotFound {
71 entity_type: "setting".into(),
72 identifier: key.into(),
73 })
74 }
75
76 pub async fn update_site_setting(
77 &self,
78 key: &str,
79 body: &serde_json::Value,
80 ) -> Result<(), CoreError> {
81 let guard = self.inner.session_client.lock().await;
82 let session = require_session(guard.as_ref())?;
83 session.set_site_setting(key, body).await?;
84 Ok(())
85 }
86}
87
88fn vpn_setting_from_raw(raw: &serde_json::Value) -> Option<VpnSetting> {
89 let object = raw.as_object()?;
90 let key = object.get("key")?.as_str()?;
91 if !VPN_SETTING_KEYS.contains(&key) {
92 return None;
93 }
94
95 let mut fields = object.clone();
96 fields.remove("_id");
97 fields.remove("key");
98 fields.remove("site_id");
99 let fields = redact_sensitive_value(&serde_json::Value::Object(fields))
100 .as_object()
101 .cloned()
102 .unwrap_or_default();
103
104 Some(VpnSetting {
105 key: key.to_owned(),
106 enabled: fields.get("enabled").and_then(serde_json::Value::as_bool),
107 fields,
108 })
109}
110
111#[cfg(test)]
112mod tests {
113 use super::vpn_setting_from_raw;
114
115 #[test]
116 fn vpn_setting_from_raw_filters_to_known_keys() {
117 let raw = serde_json::json!({
118 "key": "teleport",
119 "enabled": true,
120 "_id": "abc123",
121 "site_id": "default",
122 });
123 let setting = vpn_setting_from_raw(&raw).expect("teleport should be recognized");
124
125 assert_eq!(setting.key, "teleport");
126 assert_eq!(setting.enabled, Some(true));
127 assert!(!setting.fields.contains_key("_id"));
128 assert!(!setting.fields.contains_key("site_id"));
129 }
130}