swagger/scan/
print.rs

1use super::*;
2use comfy_table::modifiers::UTF8_ROUND_CORNERS;
3use comfy_table::presets::UTF8_FULL;
4use comfy_table::*;
5pub const LEFT_PAD: usize = 40;
6pub const TBL_LEN: usize = 190;
7pub const URL_LEN: usize = 75;
8pub fn print_active_alerts(checks: Vec<ActiveChecks>) {
9    let mut table = Table::new();
10    table
11        .load_preset(UTF8_FULL)
12        .apply_modifier(UTF8_ROUND_CORNERS)
13        .set_content_arrangement(ContentArrangement::Dynamic)
14        .set_header(vec!["Check", "Top Severity", "Alerts"]);
15    for check in checks {
16        table.add_row(vec![
17            Cell::new(check.name()).add_attribute(Attribute::Bold),
18            check.top_severity().printable(),
19            check.alerts_text(),
20        ]);
21    }
22    println!("{table}");
23}
24pub fn print_active_alerts_verbose(checks: Vec<ActiveChecks>) {
25    let mut table = Table::new();
26    table
27        .load_preset(UTF8_FULL)
28        .apply_modifier(UTF8_ROUND_CORNERS)
29        .set_content_arrangement(ContentArrangement::Dynamic)
30        .set_header(vec![
31            "Check",
32            "Severity",
33            "Description",
34            "Location",
35            "Certainty",
36        ]);
37    for check in checks {
38        for alert in check.inner() {
39            table.add_row(vec![
40                Cell::new(check.name()).add_attribute(Attribute::Bold),
41                alert.level.printable(),
42                Cell::new(alert.description).add_attribute(Attribute::Bold),
43                Cell::new(alert.location).add_attribute(Attribute::Bold),
44                alert.certainty.printable(),
45            ]);
46        }
47    }
48    println!("{table}");
49}
50pub fn print_passive_alerts(checks: Vec<PassiveChecks>) {
51    let mut table = Table::new();
52    table
53        .load_preset(UTF8_FULL)
54        .apply_modifier(UTF8_ROUND_CORNERS)
55        .set_content_arrangement(ContentArrangement::Dynamic)
56        .set_header(vec!["Check", "Top Severity", "Alerts", "Description"]);
57    for check in checks {
58        table.add_row(vec![
59            Cell::new(check.name()).add_attribute(Attribute::Bold),
60            check.top_severity().printable(),
61            check.alerts_text(),
62            Cell::new(check.description()).add_attribute(Attribute::Bold),
63        ]);
64    }
65    println!("{table}");
66}
67pub fn print_passive_alerts_verbose(checks: Vec<PassiveChecks>) {
68    let mut table = Table::new();
69    table
70        .load_preset(UTF8_FULL)
71        .apply_modifier(UTF8_ROUND_CORNERS)
72        .set_content_arrangement(ContentArrangement::Dynamic)
73        .set_header(vec!["Check", "Severity", "Description", "Location"]);
74    for check in checks {
75        for alert in check.inner() {
76            table.add_row(vec![
77                Cell::new(check.name()).add_attribute(Attribute::Bold),
78                alert.level.printable(),
79                Cell::new(alert.description).add_attribute(Attribute::Bold),
80                Cell::new(trim_location(alert.location)).add_attribute(Attribute::Bold),
81            ]);
82        }
83    }
84    println!("{table}");
85}
86fn prep_param(param: &ParamForTable) -> (String, String, String, String, String, String, String) {
87    let max = if let Some(m) = param.max {
88        m.to_string()
89    } else {
90        "NULL".to_string()
91    };
92    let min = if let Some(m) = param.min {
93        m.to_string()
94    } else {
95        "NULL".to_string()
96    };
97    let mut statuses = String::new();
98    let mut dms = String::new();
99    let mut eps = String::new();
100    let mut parents = String::new();
101    let mut children = String::new();
102    for status in &param.statuses {
103        statuses.push_str(status);
104        statuses.push('\n');
105    }
106    for dm in &param.dms {
107        dms.push_str(&format!("{:?}", dm));
108        dms.push('\n');
109    }
110    for ep in &param.eps {
111        eps.push_str(ep);
112        eps.push('\n');
113    }
114    for parent in &param.parents {
115        parents.push_str(parent);
116        parents.push('\n');
117    }
118    for child in &param.children {
119        children.push_str(child);
120        children.push('\n');
121    }
122    (min, max, statuses, dms, eps, parents, children)
123}
124// NOT YET USABLE SINCE THERE IS NO WAY FOR MULTICOLORING ONE CELL
125pub fn print_param_table(params: &Vec<ParamForTable>) {
126    let mut table = Table::new();
127    table
128        .load_preset(UTF8_FULL)
129        .apply_modifier(UTF8_ROUND_CORNERS)
130        .set_content_arrangement(ContentArrangement::Dynamic)
131        .set_header(vec![
132            "Name",
133            "Type",
134            "Statuses",
135            "Delivery Methods",
136            "Endpoints",
137            "Parents",
138            "Children",
139            "Min-Max",
140        ]);
141    for param in params {
142        let (min, max, statuses, dms, eps, parents, children) = prep_param(param);
143        table.add_row(vec![
144            Cell::new(param.name.clone()).add_attribute(Attribute::Bold),
145            Cell::new(param.param_type.clone()).add_attribute(Attribute::Bold),
146            Cell::new(statuses).add_attribute(Attribute::Bold),
147            Cell::new(dms).add_attribute(Attribute::Bold),
148            Cell::new(eps).add_attribute(Attribute::Bold),
149            Cell::new(parents).add_attribute(Attribute::Bold),
150            Cell::new(children).add_attribute(Attribute::Bold),
151            Cell::new(format!("{}-{}", min, max)).add_attribute(Attribute::Bold),
152        ]);
153    }
154    println!("{table}");
155}
156fn prep_ep(eps: &EpForTable) -> (String, String, String, String, String, String) {
157    let mut q_p = String::new();
158    let mut h_p = String::new();
159    let mut r_b_p = String::new();
160    let mut r_p = String::new();
161    let mut statuses = String::new();
162    let mut methods = String::new();
163    for method in &eps.ops {
164        methods.push_str(&method.to_string());
165        methods.push('\n');
166    }
167    for status in &eps.statuses {
168        statuses.push_str(status);
169        statuses.push('\n');
170    }
171    for p in &eps.query_params {
172        q_p.push_str(&p.to_string());
173        q_p.push('\n');
174    }
175    for p in &eps.headers_params {
176        h_p.push_str(p);
177        h_p.push('\n');
178    }
179    for p in &eps.req_body_params {
180        r_b_p.push_str(p);
181        r_b_p.push('\n');
182    }
183    for p in &eps.res_params {
184        r_p.push_str(p);
185        r_p.push('\n');
186    }
187    (methods, q_p, h_p, r_b_p, r_p, statuses)
188}
189// NOT YET USABLE SINCE THERE IS NO WAY FOR MULTICOLORING ONE CELL
190pub fn print_ep_table(eps: &Vec<EpForTable>) {
191    let mut table = Table::new();
192    table
193        .load_preset(UTF8_FULL)
194        .apply_modifier(UTF8_ROUND_CORNERS)
195        .set_content_arrangement(ContentArrangement::Dynamic)
196        .set_header(vec![
197            "Path",
198            "Methods",
199            "Query Params",
200            "Header Params",
201            "Body Params",
202            "Response Params",
203            "Statuses",
204        ]);
205    for ep in eps {
206        let (methods, q_p, h_p, r_b_p, r_p, statuses) = prep_ep(ep);
207        table.add_row(vec![
208            Cell::new(ep.path.clone()).add_attribute(Attribute::Bold),
209            Cell::new(methods).add_attribute(Attribute::Bold),
210            Cell::new(q_p).add_attribute(Attribute::Bold),
211            Cell::new(h_p).add_attribute(Attribute::Bold),
212            Cell::new(r_b_p).add_attribute(Attribute::Bold),
213            Cell::new(r_p).add_attribute(Attribute::Bold),
214            Cell::new(statuses).add_attribute(Attribute::Bold),
215        ]);
216    }
217    println!("{table}");
218}
219fn trim_location(loc: String) -> String {
220    loc.replace("swagger root", "")
221        .replace("swagger rooot", "")
222        .replace("swagger", "")
223        .replace("media type:application/json", "")
224        .replace("response status", "status")
225}
226impl Level {
227    pub fn printable(&self) -> Cell {
228        match self {
229            Self::Info => Cell::new("INFO")
230                .fg(Color::Blue)
231                .add_attribute(Attribute::Bold),
232            Self::Low => Cell::new("LOW")
233                .fg(Color::Yellow)
234                .add_attribute(Attribute::Bold),
235            Self::Medium => Cell::new("MEDIUM")
236                .fg(Color::Rgb {
237                    r: 255,
238                    g: 167,
239                    b: 38,
240                })
241                .add_attribute(Attribute::Bold),
242            Self::High => Cell::new("HIGH")
243                .fg(Color::Red)
244                .add_attribute(Attribute::Bold),
245            Self::Critical => Cell::new("CRITICAL")
246                .fg(Color::Black)
247                .add_attribute(Attribute::Bold),
248        }
249    }
250}
251impl Certainty {
252    pub fn printable(&self) -> Cell {
253        match self {
254            Self::Low => Cell::new("LOW")
255                .fg(Color::DarkGrey)
256                .add_attribute(Attribute::Bold),
257            Self::Medium => Cell::new("MEDIUM")
258                .fg(Color::DarkGrey)
259                .add_attribute(Attribute::Bold),
260            Self::High => Cell::new("HIGH")
261                .fg(Color::DarkGrey)
262                .add_attribute(Attribute::Bold),
263            Self::Certain => Cell::new("CERTAIN")
264                .fg(Color::DarkGrey)
265                .add_attribute(Attribute::Bold),
266            Self::Passive => Cell::new(""),
267        }
268    }
269}
270/*
271//pub const LEFT_PAD: usize = 40;
272//pub const TBL_LEN: usize = 190;
273//pub const URL_LEN: usize = 75;
274pub fn print_checks_table<T>(checks: &[T])
275where T:fmt::Display+Check{
276    println!(
277        "{:pad$}| RESULT | TOP SEVERITY | ALERTS  |DESCRIPTION\n{:-<table_len$}",
278        "CHECK",
279        "",
280        pad = LEFT_PAD,
281        table_len = TBL_LEN
282    );
283    for check in checks {
284        println!("{}", check);
285    }
286}
287pub fn print_failed_checks_table<T>(checks: &[T])
288where T:fmt::Display+Check{
289    println!(
290        "{:pad$}| RESULT | TOP SEVERITY | ALERTS  |DESCRIPTION\n{:-<table_len$}",
291        "CHECK",
292        "",
293        pad = LEFT_PAD,
294        table_len = TBL_LEN
295    );
296    for check in checks {
297        if check.result() == "FAILED" {
298            println!("{}", check);
299        }
300    }
301}
302fn split_text_to_lines(string:&str)->Vec<String>{
303    let mut new_vec = vec![];
304    let mut new_str = String::new();
305    let line_len = 75;
306    let mut c = 0;
307    for t in string.split(' '){
308        if !t.trim().is_empty(){
309            c+=t.len()+1;
310            if c>line_len{
311                c = t.len();
312                new_str.pop();
313                new_vec.push(new_str);
314                new_str = format!(" {}",t);
315            }else{
316                new_str.push_str(&format!("{} ",t.trim()));
317            }
318        }
319    }
320    new_vec.push(new_str);
321    new_vec
322}
323pub fn print_alerts_table(checks: &[PassiveChecks]) {
324    println!(
325        "{:pad$}| LEVEL   |{:75}|DESCRIPTION\n{:-<table_len$}",
326        "CHECK",
327        "LOCATION",
328        pad = 30,
329        table_len = TBL_LEN
330    );
331    for check in checks {
332        if check.result() == "FAILED" {
333            for alert in check.inner() {
334                println!("{:pad$}|{}", check.name().cyan().bold(), alert, pad = 30)
335            }
336        }
337    }
338}
339
340pub fn print_attack_alerts_table(checks: &[ActiveChecks]) {
341    println!(
342        "{:pad$}| SEVERITY | CERTAINTY |{:thing$}|DESCRIPTION\n{:-<table_len$}",
343        "CHECK",
344        "LOCATION",
345        "",
346        table_len = TBL_LEN,
347        pad = 30,
348        thing = URL_LEN
349    );
350    for check in checks {
351        if check.result() == "FAILED" {
352            for _ in check.inner() {
353                // println!("{:pad$}|{}", check.name().cyan().bold(), alert, pad = 30)
354                println!("{}",serde_json::to_string(&check).unwrap());
355            }
356        }
357    }
358}
359
360impl fmt::Display for PassiveChecks {
361    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
362        if self.result() == "PASSED" {
363            write!(
364                f,
365                "{:pad$}| {} |    {:8}  |  {:5}  |{}\n{:-<table_len$}",
366                self.name().bold(),
367                self.result().green().bold().underline(),
368                "NONE".blue().bold(),
369                self.alerts_text(),
370                self.description(),
371                "",
372                pad = LEFT_PAD,
373                table_len = TBL_LEN
374            )
375        } else if self.result() == "FAILED" {
376            write!(
377                f,
378                "{:pad$}| {} |    {}  |  {:5}  |{}\n{:-<table_len$}",
379                self.name().bold(),
380                self.result().red().bold().underline(),
381                self.top_severity(),
382                self.alerts_text(),
383                self.description(),
384                "",
385                pad = LEFT_PAD,
386                table_len = TBL_LEN
387            )
388        } else {
389            write!(f, "")
390        }
391    }
392}
393impl fmt::Display for ActiveChecks {
394    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
395        if self.result() == "PASSED" {
396            write!(
397                f,
398                "{:pad$}| {} |    {:8}  |  {:5}  |{}\n{:-<table_len$}",
399                self.name().bold(),
400                self.result().green().bold().underline(),
401                "NONE".blue().bold(),
402                self.alerts_text(),
403                self.description(),
404                "",
405                pad = LEFT_PAD,
406                table_len = TBL_LEN
407            )
408        } else if self.result() == "FAILED" {
409            write!(
410                f,
411                "{:pad$}| {} |    {}  |  {:5}  |{}\n{:-<table_len$}",
412                self.name().bold(),
413                self.result().red().bold().underline(),
414                self.top_severity(),
415                self.alerts_text(),
416                self.description(),
417                "",
418                pad = LEFT_PAD,
419                table_len = TBL_LEN
420            )
421        } else {
422            write!(f, "")
423        }
424    }
425}
426impl fmt::Display for Alert {
427    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
428        if self.certainty==Certainty::Passive{
429            let location = self
430                .location
431                .replace("swagger root", "")
432                .replace("swagger rooot", "")
433                .replace("swagger", "")
434                .replace("media type:application/json", "")
435                .replace("response status", "status");
436            let mut string = String::new();
437            let location = split_text_to_lines(&location);
438            string.push_str(&format!(
439                " {:10}|{:75}|  {}\n",
440                self.level,
441                location[0].bright_magenta().bold(),
442                self.description.bright_red().bold(),
443            ));
444            for loc in location.iter().skip(1){
445                string.push_str(&format!(
446                    "{:30}|{:9}|{:75}|  {}\n",
447                    "",
448                    "",
449                    loc.bright_magenta().bold(),
450                    ""
451                ));
452            }
453            string.push_str(&format!("\n{:-<190}",""));
454            write!(f,"{}",string)
455        }else{
456            /*write!(
457                f,
458                "  {}| {}  |{:thing$}|  {:}\n{:-<table_len$}",
459                self.level,
460                self.certainty,
461                self.location.bright_magenta().bold(),
462                self.description.bright_red().bold(),
463                "",
464                thing=URL_LEN,
465                table_len = TBL_LEN
466            )*/
467            write!(f,"")
468        }
469    }
470}
471impl fmt::Display for Level {
472    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
473        match self {
474            Self::Info => write!(f, "{:8}", "INFO".blue().bold()),
475            Self::Low => write!(f, "{:8}", "LOW".yellow().bold()),
476            Self::Medium => write!(f, "{:8}", "MEDIUM".truecolor(255, 167, 38).bold()),
477            Self::High => write!(f, "{:8}", "HIGH".red().bold()),
478            Self::Critical => write!(f, "{:8}", "CRITICAL".red().bold().blink()),
479        }
480    }
481}
482impl fmt::Display for Certainty {
483    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
484        match self {
485            Self::Low => write!(f, "{:8}", "LOW".bright_black().bold()),
486            Self::Medium => write!(f, "{:8}", "MEDIUM".bright_black()/*.truecolor(255, 167, 38)*/.bold()),
487            Self::High => write!(f, "{:8}", "HIGH".bright_black().bold()),
488            Self::Certain => write!(f, "{:8}", "CERTAIN".bright_black().bold()),
489            Self::Passive=> write!(f, ""),
490        }
491    }
492}
493*/