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