cli/
config.rs

1use super::*;
2use std::fs::File;
3use std::io::{Read, Write};
4use std::path::Path;
5use swagger::{PassiveChecks, PassiveScanType};
6
7const TOKEN_FILE: &str = ".cherrybomb/token.txt";
8#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
9pub struct Config {
10    pub scan_type: PassiveScanType,
11    //for now description
12    pub alerts_ignore: Vec<String>,
13    pub fail_on_info: bool,
14}
15impl Default for Config {
16    fn default() -> Self {
17        Config {
18            scan_type: PassiveScanType::Full,
19            alerts_ignore: vec![],
20            fail_on_info: true,
21        }
22    }
23}
24#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
25#[serde(untagged)]
26pub enum StrScanType {
27    Full(String),
28    Partial(Vec<String>),
29}
30#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
31pub struct ConfigStr {
32    scan_type: StrScanType,
33    pub alerts_ignore: Vec<String>,
34    pub fail_on_info: bool,
35}
36impl Default for ConfigStr {
37    fn default() -> Self {
38        ConfigStr {
39            scan_type: StrScanType::Full("Full".to_string()),
40            alerts_ignore: vec![],
41            fail_on_info: true,
42        }
43    }
44}
45impl Config {
46    fn from_conf_str(conf_str: ConfigStr) -> Config {
47        let scan_type = match conf_str.scan_type {
48            StrScanType::Full(_) => PassiveScanType::Full,
49            StrScanType::Partial(vec) => PassiveScanType::Partial(
50                vec.iter()
51                    .filter_map(|check| {
52                        let c = PassiveChecks::from_string(check);
53                        if c.is_none() {
54                            println!(
55                                "Check name: {} does not exist, the config will load without it.",
56                                check
57                            );
58                        }
59                        c
60                    })
61                    .collect(),
62            ),
63        };
64        Config {
65            scan_type,
66            alerts_ignore: conf_str.alerts_ignore,
67            fail_on_info: conf_str.fail_on_info,
68        }
69    }
70    pub fn from_file(file: &str) -> Option<Config> {
71        let mut filename = dirs::home_dir().unwrap();
72        let dir = dirs::home_dir().unwrap();
73        filename.push(file);
74        let mut file = match File::open(&mut filename) {
75            Ok(f) => f,
76            Err(_) => {
77                let mut f = if let Ok(ff) = File::create(&filename) {
78                    ff
79                } else {
80                    match std::fs::create_dir(dir) {
81                        Ok(_) => {
82                            if let Ok(ff) = File::create(filename) {
83                                ff
84                            } else {
85                                println!("Could not create config file, please make sure the cherrybomb dir is set");
86                                return None;
87                            }
88                        }
89                        Err(_) => {
90                            println!("Could not create config file, please make sure the cherrybomb dir is set");
91                            return None;
92                        }
93                    }
94                };
95                f.write_all(
96                    serde_json::to_string(&Config::default())
97                        .unwrap()
98                        .as_bytes(),
99                )
100                .unwrap();
101                return Some(Config::default());
102            }
103        };
104        let mut file_data = String::new();
105        match file.read_to_string(&mut file_data) {
106            Ok(_) => (),
107            Err(_) => {
108                print_err("Could not read data from config file");
109                return None;
110            }
111        };
112        if let Ok(conf) = serde_json::from_str::<ConfigStr>(&file_data) {
113            Some(Config::from_conf_str(conf))
114        } else {
115            println!(
116                "Config does not match format, go to our docs on github for further explanation"
117            );
118            None
119        }
120    }
121}
122async fn create_token(filename: &Path, dir: &Path) -> bool {
123    use uuid::Uuid;
124    let mut file = match File::create(filename) {
125        Ok(f) => f,
126        Err(_) => match std::fs::create_dir(dir) {
127            Ok(_) => match File::create(filename) {
128                Ok(f) => f,
129                Err(_) => {
130                    return false;
131                }
132            },
133            Err(_) => {
134                return false;
135            }
136        },
137    };
138    file.write_all(Uuid::new_v4().to_string().as_bytes())
139        .unwrap_or_default();
140    true
141}
142async fn get_token() -> String {
143    let mut filename = dirs::home_dir().unwrap();
144    filename.push(TOKEN_FILE);
145    let mut dir = dirs::home_dir().unwrap();
146    dir.push(".cherrybomb");
147    let mut file = match File::open(&filename) {
148        Ok(f) => f,
149        Err(_) => {
150            if create_token(&filename, &dir).await {
151                match File::open(&filename) {
152                    Ok(f) => f,
153                    Err(_) => {
154                        return String::new();
155                    }
156                }
157            } else {
158                return String::new();
159            }
160        }
161    };
162    let mut token = String::new();
163    match file.read_to_string(&mut token) {
164        Ok(_) => (),
165        Err(_) => {
166            return String::new();
167        }
168    }
169    token
170}
171pub async fn try_send_telemetry(no_tel: Option<bool>, action: &str) {
172    if let Some(t) = no_tel {
173        if t {
174            return;
175        }
176    }
177    let token = get_token().await;
178    let client = reqwest::Client::new();
179    let _ = client
180        .post("https://cherrybomb.blstsecurity.com/tel")
181        .body(format!(
182            "{{\"client_token\":\"{}\",\"event\":\"{}\"}}",
183            token, action
184        ))
185        .send()
186        .await;
187}