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 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}