main
py 140 lines 4.26 KB
Raw
1 import asyncio
2 import json
3 import os
4 import subprocess
5 from concurrent.futures import ThreadPoolExecutor
6
7 import aiofiles
8 from fastapi import HTTPException
9 from loguru import logger
10
11 from app.integrations.scoutsuite.schema.scoutsuite import AWSScoutSuiteReportRequest
12 from app.integrations.scoutsuite.schema.scoutsuite import AzureScoutSuiteReportRequest
13 from app.integrations.scoutsuite.schema.scoutsuite import GCPScoutSuiteJSON
14 from app.integrations.scoutsuite.schema.scoutsuite import GCPScoutSuiteReportRequest
15
16
17 async def generate_aws_report_background(request: AWSScoutSuiteReportRequest):
18 logger.info("Generating AWS ScoutSuite report in the background")
19
20 command = construct_aws_command(request)
21 await run_command_in_background(command)
22
23
24 def construct_aws_command(request: AWSScoutSuiteReportRequest):
25 """Construct the scout command."""
26 return [
27 "scout",
28 "aws",
29 "--access-key-id",
30 request.access_key_id,
31 "--secret-access-key",
32 request.secret_access_key,
33 "--report-name",
34 request.report_name,
35 "--force",
36 "--no-browser",
37 ]
38
39
40 async def generate_azure_report_background(request: AzureScoutSuiteReportRequest):
41 logger.info("Generating Azure ScoutSuite report in the background")
42
43 command = construct_azure_command(request)
44 await run_command_in_background(command)
45
46
47 def construct_azure_command(request: AzureScoutSuiteReportRequest):
48 """Construct the scout command."""
49 return [
50 "scout",
51 "azure",
52 "--user-account",
53 "--tenant",
54 request.tenant_id,
55 "--username",
56 request.username,
57 "--password",
58 request.password,
59 "--report-name",
60 request.report_name,
61 "--force",
62 "--no-browser",
63 ]
64
65
66 async def generate_gcp_report_background(request: GCPScoutSuiteReportRequest):
67 logger.info("Generating GCP ScoutSuite report in the background")
68
69 command = construct_gcp_command(request)
70 await run_command_in_background(command)
71
72 # Delete the file after the report is generated
73 try:
74 os.remove(request.file_path)
75 logger.info(f"Deleted GCP credentials file: {request.file_path}")
76 except Exception as e:
77 logger.error(f"Error deleting GCP credentials file: {e}")
78
79
80 def construct_gcp_command(request: GCPScoutSuiteReportRequest):
81 """Construct the scout command."""
82 return [
83 "scout",
84 "gcp",
85 "--service-account",
86 request.file_path,
87 "--all-projects",
88 "--report-name",
89 request.report_name,
90 "--force",
91 "--no-browser",
92 ]
93
94
95 def run_command(command):
96 """Run the command and handle the output."""
97 process = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
98 stdout, stderr = process.communicate()
99
100 if process.returncode != 0:
101 logger.error(f"ScoutSuite report generation failed: {stderr.decode()}")
102 return None
103
104 logger.info("ScoutSuite report generated successfully")
105 return None
106
107
108 async def run_command_in_background(command):
109 """Run the command in a separate thread."""
110 with ThreadPoolExecutor() as executor:
111 loop = asyncio.get_event_loop()
112 await loop.run_in_executor(executor, lambda: run_command(command))
113
114
115 async def read_json_file(contents: bytes) -> dict:
116 """Read and parse the JSON file."""
117 try:
118 return json.loads(contents)
119 except json.JSONDecodeError as e:
120 raise HTTPException(status_code=400, detail=f"Invalid JSON file - {str(e)}")
121
122
123 def validate_json_data(data: dict):
124 """Validate the JSON data against the GCPScoutSuiteJSON model."""
125 try:
126 GCPScoutSuiteJSON(**data)
127 except Exception as e:
128 raise HTTPException(status_code=400, detail=f"JSON file does not have the correct format and fields - {str(e)}")
129
130
131 async def save_file_to_directory(contents: bytes, directory: str, filename: str) -> str:
132 """Save the uploaded file to the specified directory."""
133 try:
134 os.makedirs(directory, exist_ok=True)
135 file_path = os.path.join(directory, filename)
136 async with aiofiles.open(file_path, "wb") as out_file:
137 await out_file.write(contents)
138 return file_path
139 except Exception as e:
140 raise HTTPException(status_code=400, detail=str(e))