1use serde::{Deserialize, Serialize};
2use std::fs::File;
3
4#[derive(Serialize, Deserialize, Debug, Clone)]
5pub struct SecurityPolicy {
6 pub revision: u64,
7 pub blocked_domains: Vec<String>,
8 pub blocked_ips: Vec<String>,
9 pub lockdown_mode: bool,
11}
12
13impl SecurityPolicy {
14 pub fn default_allow() -> Self {
15 Self {
16 revision: 0,
17 blocked_domains: vec![],
18 blocked_ips: vec![],
19 lockdown_mode: false,
20 }
21 }
22}
23
24pub fn expand_path(path: &str) -> String {
25 if path.starts_with("~/")
26 && let Some(home) = dirs::home_dir()
27 && let Some(home_str) = home.to_str()
29 {
30 return path.replacen("~", home_str, 1);
31 }
32
33 path.to_string()
34}
35
36pub async fn load_policy(raw_path: &str) -> SecurityPolicy {
37 let path_string = expand_path(raw_path);
38 let path = path_string.as_str();
39
40 if path.starts_with("http://") || path.starts_with("https://") {
41 match reqwest::get(path).await {
42 Ok(resp) => match resp.json::<SecurityPolicy>().await {
43 Ok(p) => {
44 log::info!("secexit policy (v{}) loaded from URL: {}", p.revision, path);
45 return p;
46 }
47 Err(e) => log::warn!("Failed to parse policy from URL {}: {}", path, e),
48 },
49 Err(e) => log::warn!("Failed to fetch policy from URL {}: {}", path, e),
50 }
51 } else {
52 if let Ok(file) = File::open(path)
53 && let Ok(p) = serde_json::from_reader::<_, SecurityPolicy>(file)
54 {
55 log::info!("secexit policy (v{}) loaded from: {}", p.revision, path);
56 return p;
57 }
58
59 log::warn!("No policy found at {}.", path);
60 }
61
62 log::warn!("Defaulting to empty policy.");
63 SecurityPolicy::default_allow()
64}