cli/
actions.rs

1use super::*;
2use std::collections::HashMap;
3use swagger::scan::active::{ActiveScan, ActiveScanType};
4use swagger::scan::passive::PassiveSwaggerScan;
5use swagger::scan::Level;
6use swagger::{Authorization, Check, EpTable, ParamTable, PassiveScanType, Swagger, OAS, OAS3_1, Server};
7
8pub fn run_passive_swagger_scan<T>(
9    scan_try: Result<PassiveSwaggerScan<T>, &'static str>,
10    verbosity: u8,
11    output_file: Option<String>,
12    passive_scan_type: PassiveScanType,
13    json: bool,
14) -> Result<i8, &'static str>
15where
16    T: OAS + Serialize + for<'de> Deserialize<'de> + std::fmt::Debug,
17{
18    let mut scan = match scan_try {
19        Ok(s) => s,
20        Err(e) => {
21            return Err(e);
22        }
23    };
24    scan.run(passive_scan_type);
25    if json {
26        let mut out_json: HashMap<&str, Vec<swagger::scan::Alert>> = HashMap::new();
27        for check in scan.passive_checks.iter() {
28            if !check.inner().is_empty() {
29                out_json.insert(check.name(), check.inner().clone());
30            }
31        }
32        print!("{}", serde_json::to_string(&out_json).unwrap());
33    } else {
34        scan.print(verbosity);
35    }
36    let failed = scan.passive_checks.iter().any(|c| c.result() == "FAILED"); //TODO support minimum level failure
37    if let Some(f) = output_file {
38        let print = if json {
39            serde_json::to_string(&scan).unwrap()
40        } else {
41            scan.print_to_file_string()
42        };
43        write_to_file(&f, print);
44    }
45    if failed {
46        Ok(101)
47    } else {
48        Ok(0)
49    }
50}
51
52pub async fn run_active_swagger_scan<T>(
53    scan_try: Result<ActiveScan<T>, &'static str>,
54    verbosity: u8,
55    output_file: Option<String>,
56    auth: Authorization,
57    scan_type: ActiveScanType,
58    json: bool,
59    _servers: Option<Vec<Server>>,
60) -> Result<i8, &'static str>
61where
62    T: OAS + Serialize + for<'de> Deserialize<'de> + std::fmt::Debug,
63{
64    let mut scan = match scan_try {
65        Ok(s) => s,
66        Err(e) => {
67            return Err(e);
68        }
69    };
70    scan.run(scan_type, &auth).await;
71    if json {
72        let mut out_json: HashMap<&str, Vec<swagger::scan::Alert>> = HashMap::new();
73        for check in scan.checks.iter() {
74            if !check.inner().is_empty() {
75                out_json.insert(check.name(), check.inner().clone());
76            }
77        }
78        print!("{}", serde_json::to_string(&out_json).unwrap());
79    } else {
80        scan.print(verbosity);
81    }
82    let failed = scan
83        .checks
84        .iter()
85        .any(|c| (c.result() == "FAILED") || (c.top_severity() > Level::Info));
86    if let Some(f) = output_file {
87        let print = scan.print_to_file_string();
88        write_to_file(&f, print);
89    }
90    if failed {
91        Ok(101)
92    } else {
93        Ok(0)
94    }
95}
96
97// todo create type, maybe add activeScanType none
98#[allow(clippy::too_many_arguments)]
99pub async fn run_swagger(
100    file: &str,
101    verbosity: u8,
102    output_file: Option<String>,
103    auth: Authorization,
104    no_active: bool,
105    active_scan_type: ActiveScanType,
106    passive_scan_type: PassiveScanType,
107    json: bool, ) -> i8 {
108    let (value, version) = if let Some((v1, v2)) = get_oas_value_version(file) {
109        (v1, v2)
110    } else { return -1 };
111    if version.starts_with("3.") {
112        if json {
113            print!("{{\"passive checks\":");
114        }
115        let passive_result = run_passive_swagger_scan::<OAS3_1>(
116            PassiveSwaggerScan::<OAS3_1>::new(value.clone()),
117            verbosity,
118            output_file.clone(),
119            passive_scan_type,
120            json,
121        );
122        if let Err(e) = passive_result {
123            print_err(e);
124            return -1;
125        }
126        if json {
127            print!(",\"active checks\":");
128        }
129        let active_result = if !no_active && value.get("servers").is_some()  {
130            run_active_swagger_scan::<OAS3_1>(
131                ActiveScan::<OAS3_1>::new(value.clone()),
132                verbosity,
133                output_file.clone(),
134                auth,
135                active_scan_type,
136                json,
137                None, // TODO ADD SUPPORT FOR SERVERS FROM CONFIG
138            )
139            .await
140        } else {
141            Ok(0)
142        };
143        if let Err(e) = active_result {
144            print_err(e);
145            return -1;
146        }
147        if json {
148            print!("}}")
149        }
150        if passive_result.unwrap() == 0 && active_result.unwrap() == 0 {
151            0i8
152        } else {
153            101i8
154        }
155    } else {
156        print_err("Unsupported OpenAPI specification version");
157        -1
158    }
159}
160
161pub fn param_table(file: &str, param: Option<String>) {
162    let (value, version) = if let Some((v1, v2)) = get_oas_value_version(file) {
163        (v1, v2)
164    } else {
165        return;
166    };
167    if version.starts_with("3.0") {
168        let table = ParamTable::new::<Swagger>(&value);
169        if let Some(p) = param {
170            table.named_param(&p).print();
171        } else {
172            table.print();
173        }
174    } else if version.starts_with("3.1") {
175        let table = ParamTable::new::<OAS3_1>(&value);
176        if let Some(p) = param {
177            table.named_param(&p).print();
178        } else {
179            table.print();
180        }
181    } else {
182        print_err("Unsupported OpenAPI specification version");
183    }
184}
185
186pub fn ep_table(file: &str, path: Option<String>) {
187    let (value, version) = if let Some((v1, v2)) = get_oas_value_version(file) {
188        (v1, v2)
189    } else {
190        return;
191    };
192    if version.starts_with("3.0") {
193        let table = EpTable::new::<Swagger>(&value);
194        if let Some(p) = path {
195            table.path_only(&p).print();
196        } else {
197            table.print();
198        }
199    } else if version.starts_with("3.1") {
200        let table = EpTable::new::<OAS3_1>(&value);
201        if let Some(p) = path {
202            table.path_only(&p).print();
203        } else {
204            table.print();
205        }
206    } else {
207        print_err("Unsupported OpenAPI specification version");
208    }
209}