|
6 | 6 |
|
7 | 7 | from datetime import datetime |
8 | 8 |
|
| 9 | +import json |
9 | 10 | import logging |
10 | 11 | import os |
11 | 12 | import platform |
12 | 13 | import subprocess |
| 14 | +import sys |
| 15 | + |
| 16 | +import requests |
13 | 17 |
|
14 | 18 |
|
15 | 19 | class BinaryDoesNotExist(Exception): |
@@ -147,3 +151,146 @@ def run_cmd_out_err(self, cmd): |
147 | 151 | """ |
148 | 152 | return subprocess.Popen(cmd, stdout=subprocess.PIPE, |
149 | 153 | stderr=subprocess.PIPE).communicate() |
| 154 | + |
| 155 | + def post_request(self, endpoint, api, data, headers=None): |
| 156 | + """ |
| 157 | + Make a post call to analytics server with given data |
| 158 | + :param endpoint: API server end point |
| 159 | + :param api: API to make POST call against |
| 160 | + :param data: JSON data needed for POST call to api endpoint |
| 161 | + :return: Tuple (status, error_if_any, status_code) |
| 162 | + where status = True/False |
| 163 | + error_if_any = string message on error, "" on success |
| 164 | + status_code = status_code returned by server |
| 165 | + """ |
| 166 | + url = requests.compat.urljoin(endpoint, api) |
| 167 | + # TODO: check if we need API key in data |
| 168 | + try: |
| 169 | + r = requests.post( |
| 170 | + url, |
| 171 | + json.dumps(data), |
| 172 | + headers=headers) |
| 173 | + except requests.exceptions.RequestException as e: |
| 174 | + error = ("Could not send POST request to URL {0}, " |
| 175 | + "with data: {1}.").format(url, str(data)) |
| 176 | + return False, error + " Error: " + str(e), 0 |
| 177 | + else: |
| 178 | + # requests.codes.ok == 200 |
| 179 | + if r.status_code == requests.codes.ok: |
| 180 | + return True, json.loads(r.text), r.status_code |
| 181 | + else: |
| 182 | + return False, "Returned {} status code for {}".format( |
| 183 | + r.status_code, url), r.status_code |
| 184 | + |
| 185 | + def get_request(self, endpoint, api, data, headers=None): |
| 186 | + """ |
| 187 | + Make a get call to analytics server |
| 188 | + :param endpoint: API server end point |
| 189 | + :param api: API to make GET call against |
| 190 | + :param data: JSON data needed for GET call |
| 191 | + :return: Tuple (status, error_if_any, status_code) |
| 192 | + where status = True/False |
| 193 | + error_if_any = string message on error, "" on success |
| 194 | + status_code = status_code returned by server |
| 195 | + """ |
| 196 | + url = requests.compat.urljoin(endpoint, api) |
| 197 | + # TODO: check if we need API key in data |
| 198 | + try: |
| 199 | + r = requests.get( |
| 200 | + url, |
| 201 | + params=data, |
| 202 | + headers=headers) |
| 203 | + |
| 204 | + except requests.exceptions.RequestException as e: |
| 205 | + error = "Failed to process URL: {} with params {}".format( |
| 206 | + url, data) |
| 207 | + return False, error + " Error: " + str(e), 0 |
| 208 | + else: |
| 209 | + # requests.codes.ok == 200 or |
| 210 | + # check for 400 code - as this is a valid response |
| 211 | + # as per the workflow |
| 212 | + if r.status_code in [requests.codes.ok, 400]: |
| 213 | + return True, json.loads(r.text), r.status_code |
| 214 | + else: |
| 215 | + msg = "Returned {} status code for {}. {}".format( |
| 216 | + r.status_code, url, r.json().get( |
| 217 | + "summary", "no summary returned from server.")) |
| 218 | + return False, msg, r.status_code |
| 219 | + |
| 220 | + def export_json_results(self, results, output_dir, output_file): |
| 221 | + """ |
| 222 | + Export given results JSON data in output_dir/output_file |
| 223 | +
|
| 224 | + :param results: JSON results to be exported |
| 225 | + :type results: dict |
| 226 | + :param output_dir: Output directory |
| 227 | + :type output_dir: str |
| 228 | + :param output_file: Output file name |
| 229 | + :type output_file: str |
| 230 | + """ |
| 231 | + os.makedirs(output_dir) |
| 232 | + |
| 233 | + result_filename = os.path.join(output_dir, output_file) |
| 234 | + |
| 235 | + with open(result_filename, "w") as f: |
| 236 | + json.dump(results, f, indent=4, separators=(",", ": ")) |
| 237 | + |
| 238 | + def template_json_data(self, scanner, scan_type='', uuid=''): |
| 239 | + """ |
| 240 | + Populate and return a template standard json data out for scanner. |
| 241 | + """ |
| 242 | + current_time = datetime.now().strftime("%Y-%m-%d-%H-%M-%S-%f") |
| 243 | + json_out = { |
| 244 | + "Start Time": current_time, |
| 245 | + "Successful": False, |
| 246 | + "Scan Type": scan_type, |
| 247 | + "UUID": uuid, |
| 248 | + "Scanner": scanner, |
| 249 | + "Scan Results": {}, |
| 250 | + "Summary": "" |
| 251 | + } |
| 252 | + return json_out |
| 253 | + |
| 254 | + def configure_stdout_logging( |
| 255 | + self, logger_name, logging_level=logging.DEBUG): |
| 256 | + """ |
| 257 | + Configures stdout logging and returns logger object |
| 258 | +
|
| 259 | + :param logger_name: Logger name |
| 260 | + :type logger_name: str |
| 261 | + :param logging_level: Logging level |
| 262 | + :type logging_level: str or int |
| 263 | +
|
| 264 | + :return: Logger object |
| 265 | + """ |
| 266 | + logger = logging.getLogger(logger_name) |
| 267 | + logger.setLevel(logging_level) |
| 268 | + # add sys.stdout stream |
| 269 | + ch = logging.StreamHandler(sys.stdout) |
| 270 | + ch.setLevel(logging.DEBUG) |
| 271 | + # add logging formatter |
| 272 | + formatter = logging.Formatter( |
| 273 | + "%(asctime)s %(levelname)s p%(process)s %(name)s %(lineno)d " |
| 274 | + "%(levelname)s - %(message)s" |
| 275 | + ) |
| 276 | + # set formatter to stream handler |
| 277 | + ch.setFormatter(formatter) |
| 278 | + # set handler to logger |
| 279 | + logger.addHandler(ch) |
| 280 | + return logger |
| 281 | + |
| 282 | + def get_env_var(self, env_var): |
| 283 | + """ |
| 284 | + Gets the given configured env_var |
| 285 | + :param env_var: Environment variable to be accessed |
| 286 | + :type env_var: str |
| 287 | +
|
| 288 | + :return: Value of given env_var |
| 289 | + :rtype: str |
| 290 | + """ |
| 291 | + if not os.environ.get(env_var, False): |
| 292 | + raise ValueError( |
| 293 | + "No value for {0} env var. Please re-run with: " |
| 294 | + "{0}=<VALUE> [..] atomic scan [..] ".format(env_var) |
| 295 | + ) |
| 296 | + return os.environ.get(env_var) |
0 commit comments