aiptx 2.0.2__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of aiptx might be problematic. Click here for more details.

Files changed (165) hide show
  1. aipt_v2/__init__.py +110 -0
  2. aipt_v2/__main__.py +24 -0
  3. aipt_v2/agents/AIPTxAgent/__init__.py +10 -0
  4. aipt_v2/agents/AIPTxAgent/aiptx_agent.py +211 -0
  5. aipt_v2/agents/__init__.py +24 -0
  6. aipt_v2/agents/base.py +520 -0
  7. aipt_v2/agents/ptt.py +406 -0
  8. aipt_v2/agents/state.py +168 -0
  9. aipt_v2/app.py +960 -0
  10. aipt_v2/browser/__init__.py +31 -0
  11. aipt_v2/browser/automation.py +458 -0
  12. aipt_v2/browser/crawler.py +453 -0
  13. aipt_v2/cli.py +321 -0
  14. aipt_v2/compliance/__init__.py +71 -0
  15. aipt_v2/compliance/compliance_report.py +449 -0
  16. aipt_v2/compliance/framework_mapper.py +424 -0
  17. aipt_v2/compliance/nist_mapping.py +345 -0
  18. aipt_v2/compliance/owasp_mapping.py +330 -0
  19. aipt_v2/compliance/pci_mapping.py +297 -0
  20. aipt_v2/config.py +288 -0
  21. aipt_v2/core/__init__.py +43 -0
  22. aipt_v2/core/agent.py +630 -0
  23. aipt_v2/core/llm.py +395 -0
  24. aipt_v2/core/memory.py +305 -0
  25. aipt_v2/core/ptt.py +329 -0
  26. aipt_v2/database/__init__.py +14 -0
  27. aipt_v2/database/models.py +232 -0
  28. aipt_v2/database/repository.py +384 -0
  29. aipt_v2/docker/__init__.py +23 -0
  30. aipt_v2/docker/builder.py +260 -0
  31. aipt_v2/docker/manager.py +222 -0
  32. aipt_v2/docker/sandbox.py +371 -0
  33. aipt_v2/evasion/__init__.py +58 -0
  34. aipt_v2/evasion/request_obfuscator.py +272 -0
  35. aipt_v2/evasion/tls_fingerprint.py +285 -0
  36. aipt_v2/evasion/ua_rotator.py +301 -0
  37. aipt_v2/evasion/waf_bypass.py +439 -0
  38. aipt_v2/execution/__init__.py +23 -0
  39. aipt_v2/execution/executor.py +302 -0
  40. aipt_v2/execution/parser.py +544 -0
  41. aipt_v2/execution/terminal.py +337 -0
  42. aipt_v2/health.py +437 -0
  43. aipt_v2/intelligence/__init__.py +85 -0
  44. aipt_v2/intelligence/auth.py +520 -0
  45. aipt_v2/intelligence/chaining.py +775 -0
  46. aipt_v2/intelligence/cve_aipt.py +334 -0
  47. aipt_v2/intelligence/cve_info.py +1111 -0
  48. aipt_v2/intelligence/rag.py +239 -0
  49. aipt_v2/intelligence/scope.py +442 -0
  50. aipt_v2/intelligence/searchers/__init__.py +5 -0
  51. aipt_v2/intelligence/searchers/exploitdb_searcher.py +523 -0
  52. aipt_v2/intelligence/searchers/github_searcher.py +467 -0
  53. aipt_v2/intelligence/searchers/google_searcher.py +281 -0
  54. aipt_v2/intelligence/tools.json +443 -0
  55. aipt_v2/intelligence/triage.py +670 -0
  56. aipt_v2/interface/__init__.py +5 -0
  57. aipt_v2/interface/cli.py +230 -0
  58. aipt_v2/interface/main.py +501 -0
  59. aipt_v2/interface/tui.py +1276 -0
  60. aipt_v2/interface/utils.py +583 -0
  61. aipt_v2/llm/__init__.py +39 -0
  62. aipt_v2/llm/config.py +26 -0
  63. aipt_v2/llm/llm.py +514 -0
  64. aipt_v2/llm/memory.py +214 -0
  65. aipt_v2/llm/request_queue.py +89 -0
  66. aipt_v2/llm/utils.py +89 -0
  67. aipt_v2/models/__init__.py +15 -0
  68. aipt_v2/models/findings.py +295 -0
  69. aipt_v2/models/phase_result.py +224 -0
  70. aipt_v2/models/scan_config.py +207 -0
  71. aipt_v2/monitoring/grafana/dashboards/aipt-dashboard.json +355 -0
  72. aipt_v2/monitoring/grafana/dashboards/default.yml +17 -0
  73. aipt_v2/monitoring/grafana/datasources/prometheus.yml +17 -0
  74. aipt_v2/monitoring/prometheus.yml +60 -0
  75. aipt_v2/orchestration/__init__.py +52 -0
  76. aipt_v2/orchestration/pipeline.py +398 -0
  77. aipt_v2/orchestration/progress.py +300 -0
  78. aipt_v2/orchestration/scheduler.py +296 -0
  79. aipt_v2/orchestrator.py +2284 -0
  80. aipt_v2/payloads/__init__.py +27 -0
  81. aipt_v2/payloads/cmdi.py +150 -0
  82. aipt_v2/payloads/sqli.py +263 -0
  83. aipt_v2/payloads/ssrf.py +204 -0
  84. aipt_v2/payloads/templates.py +222 -0
  85. aipt_v2/payloads/traversal.py +166 -0
  86. aipt_v2/payloads/xss.py +204 -0
  87. aipt_v2/prompts/__init__.py +60 -0
  88. aipt_v2/proxy/__init__.py +29 -0
  89. aipt_v2/proxy/history.py +352 -0
  90. aipt_v2/proxy/interceptor.py +452 -0
  91. aipt_v2/recon/__init__.py +44 -0
  92. aipt_v2/recon/dns.py +241 -0
  93. aipt_v2/recon/osint.py +367 -0
  94. aipt_v2/recon/subdomain.py +372 -0
  95. aipt_v2/recon/tech_detect.py +311 -0
  96. aipt_v2/reports/__init__.py +17 -0
  97. aipt_v2/reports/generator.py +313 -0
  98. aipt_v2/reports/html_report.py +378 -0
  99. aipt_v2/runtime/__init__.py +44 -0
  100. aipt_v2/runtime/base.py +30 -0
  101. aipt_v2/runtime/docker.py +401 -0
  102. aipt_v2/runtime/local.py +346 -0
  103. aipt_v2/runtime/tool_server.py +205 -0
  104. aipt_v2/scanners/__init__.py +28 -0
  105. aipt_v2/scanners/base.py +273 -0
  106. aipt_v2/scanners/nikto.py +244 -0
  107. aipt_v2/scanners/nmap.py +402 -0
  108. aipt_v2/scanners/nuclei.py +273 -0
  109. aipt_v2/scanners/web.py +454 -0
  110. aipt_v2/scripts/security_audit.py +366 -0
  111. aipt_v2/telemetry/__init__.py +7 -0
  112. aipt_v2/telemetry/tracer.py +347 -0
  113. aipt_v2/terminal/__init__.py +28 -0
  114. aipt_v2/terminal/executor.py +400 -0
  115. aipt_v2/terminal/sandbox.py +350 -0
  116. aipt_v2/tools/__init__.py +44 -0
  117. aipt_v2/tools/active_directory/__init__.py +78 -0
  118. aipt_v2/tools/active_directory/ad_config.py +238 -0
  119. aipt_v2/tools/active_directory/bloodhound_wrapper.py +447 -0
  120. aipt_v2/tools/active_directory/kerberos_attacks.py +430 -0
  121. aipt_v2/tools/active_directory/ldap_enum.py +533 -0
  122. aipt_v2/tools/active_directory/smb_attacks.py +505 -0
  123. aipt_v2/tools/agents_graph/__init__.py +19 -0
  124. aipt_v2/tools/agents_graph/agents_graph_actions.py +69 -0
  125. aipt_v2/tools/api_security/__init__.py +76 -0
  126. aipt_v2/tools/api_security/api_discovery.py +608 -0
  127. aipt_v2/tools/api_security/graphql_scanner.py +622 -0
  128. aipt_v2/tools/api_security/jwt_analyzer.py +577 -0
  129. aipt_v2/tools/api_security/openapi_fuzzer.py +761 -0
  130. aipt_v2/tools/browser/__init__.py +5 -0
  131. aipt_v2/tools/browser/browser_actions.py +238 -0
  132. aipt_v2/tools/browser/browser_instance.py +535 -0
  133. aipt_v2/tools/browser/tab_manager.py +344 -0
  134. aipt_v2/tools/cloud/__init__.py +70 -0
  135. aipt_v2/tools/cloud/cloud_config.py +273 -0
  136. aipt_v2/tools/cloud/cloud_scanner.py +639 -0
  137. aipt_v2/tools/cloud/prowler_tool.py +571 -0
  138. aipt_v2/tools/cloud/scoutsuite_tool.py +359 -0
  139. aipt_v2/tools/executor.py +307 -0
  140. aipt_v2/tools/parser.py +408 -0
  141. aipt_v2/tools/proxy/__init__.py +5 -0
  142. aipt_v2/tools/proxy/proxy_actions.py +103 -0
  143. aipt_v2/tools/proxy/proxy_manager.py +789 -0
  144. aipt_v2/tools/registry.py +196 -0
  145. aipt_v2/tools/scanners/__init__.py +343 -0
  146. aipt_v2/tools/scanners/acunetix_tool.py +712 -0
  147. aipt_v2/tools/scanners/burp_tool.py +631 -0
  148. aipt_v2/tools/scanners/config.py +156 -0
  149. aipt_v2/tools/scanners/nessus_tool.py +588 -0
  150. aipt_v2/tools/scanners/zap_tool.py +612 -0
  151. aipt_v2/tools/terminal/__init__.py +5 -0
  152. aipt_v2/tools/terminal/terminal_actions.py +37 -0
  153. aipt_v2/tools/terminal/terminal_manager.py +153 -0
  154. aipt_v2/tools/terminal/terminal_session.py +449 -0
  155. aipt_v2/tools/tool_processing.py +108 -0
  156. aipt_v2/utils/__init__.py +17 -0
  157. aipt_v2/utils/logging.py +201 -0
  158. aipt_v2/utils/model_manager.py +187 -0
  159. aipt_v2/utils/searchers/__init__.py +269 -0
  160. aiptx-2.0.2.dist-info/METADATA +324 -0
  161. aiptx-2.0.2.dist-info/RECORD +165 -0
  162. aiptx-2.0.2.dist-info/WHEEL +5 -0
  163. aiptx-2.0.2.dist-info/entry_points.txt +7 -0
  164. aiptx-2.0.2.dist-info/licenses/LICENSE +21 -0
  165. aiptx-2.0.2.dist-info/top_level.txt +1 -0
@@ -0,0 +1,452 @@
1
+ """
2
+ AIPT Proxy Interceptor
3
+
4
+ HTTP/HTTPS traffic interception using mitmproxy.
5
+ """
6
+ from __future__ import annotations
7
+
8
+ import asyncio
9
+ import json
10
+ import logging
11
+ import os
12
+ import tempfile
13
+ import threading
14
+ from dataclasses import dataclass, field
15
+ from datetime import datetime
16
+ from typing import Any, Callable, Optional
17
+ from urllib.parse import urlparse
18
+
19
+ logger = logging.getLogger(__name__)
20
+
21
+ # mitmproxy import with fallback
22
+ try:
23
+ from mitmproxy import http, options
24
+ from mitmproxy.tools import dump
25
+ MITMPROXY_AVAILABLE = True
26
+ except ImportError:
27
+ MITMPROXY_AVAILABLE = False
28
+ logger.warning("mitmproxy not installed. Install with: pip install mitmproxy")
29
+
30
+
31
+ @dataclass
32
+ class InterceptedRequest:
33
+ """Captured HTTP request"""
34
+ id: str
35
+ timestamp: datetime
36
+ method: str
37
+ url: str
38
+ host: str
39
+ path: str
40
+ headers: dict[str, str]
41
+ body: bytes = b""
42
+ query_params: dict[str, list[str]] = field(default_factory=dict)
43
+ cookies: dict[str, str] = field(default_factory=dict)
44
+
45
+ # Classification
46
+ content_type: str = ""
47
+ is_json: bool = False
48
+ is_form: bool = False
49
+ is_multipart: bool = False
50
+
51
+ def to_dict(self) -> dict:
52
+ return {
53
+ "id": self.id,
54
+ "timestamp": self.timestamp.isoformat(),
55
+ "method": self.method,
56
+ "url": self.url,
57
+ "host": self.host,
58
+ "path": self.path,
59
+ "headers": self.headers,
60
+ "body_size": len(self.body),
61
+ "content_type": self.content_type,
62
+ }
63
+
64
+ def get_body_text(self) -> str:
65
+ """Get body as text"""
66
+ try:
67
+ return self.body.decode("utf-8")
68
+ except UnicodeDecodeError:
69
+ return f"[Binary: {len(self.body)} bytes]"
70
+
71
+ def get_body_json(self) -> Optional[dict]:
72
+ """Parse body as JSON"""
73
+ if self.is_json:
74
+ try:
75
+ return json.loads(self.body)
76
+ except json.JSONDecodeError:
77
+ pass
78
+ return None
79
+
80
+
81
+ @dataclass
82
+ class InterceptedResponse:
83
+ """Captured HTTP response"""
84
+ request_id: str
85
+ timestamp: datetime
86
+ status_code: int
87
+ reason: str
88
+ headers: dict[str, str]
89
+ body: bytes = b""
90
+
91
+ # Timing
92
+ response_time_ms: float = 0.0
93
+
94
+ # Classification
95
+ content_type: str = ""
96
+ is_json: bool = False
97
+ is_html: bool = False
98
+
99
+ def to_dict(self) -> dict:
100
+ return {
101
+ "request_id": self.request_id,
102
+ "timestamp": self.timestamp.isoformat(),
103
+ "status_code": self.status_code,
104
+ "reason": self.reason,
105
+ "headers": self.headers,
106
+ "body_size": len(self.body),
107
+ "response_time_ms": self.response_time_ms,
108
+ "content_type": self.content_type,
109
+ }
110
+
111
+ def get_body_text(self) -> str:
112
+ """Get body as text"""
113
+ try:
114
+ return self.body.decode("utf-8")
115
+ except UnicodeDecodeError:
116
+ return f"[Binary: {len(self.body)} bytes]"
117
+
118
+
119
+ @dataclass
120
+ class ProxyConfig:
121
+ """Proxy configuration"""
122
+ listen_host: str = "127.0.0.1"
123
+ listen_port: int = 8080
124
+
125
+ # SSL/TLS
126
+ ssl_insecure: bool = True # Accept invalid certs from upstream
127
+
128
+ # Filtering
129
+ include_hosts: list[str] = field(default_factory=list)
130
+ exclude_hosts: list[str] = field(default_factory=lambda: [
131
+ "*.google.com",
132
+ "*.googleapis.com",
133
+ "*.gstatic.com",
134
+ "*.doubleclick.net",
135
+ "*.google-analytics.com",
136
+ ])
137
+
138
+ # Capture settings
139
+ capture_requests: bool = True
140
+ capture_responses: bool = True
141
+ max_body_size: int = 10 * 1024 * 1024 # 10MB
142
+
143
+ # Modification
144
+ inject_headers: dict[str, str] = field(default_factory=dict)
145
+ remove_headers: list[str] = field(default_factory=list)
146
+
147
+
148
+ class ProxyInterceptor:
149
+ """
150
+ HTTP/HTTPS traffic interceptor.
151
+
152
+ Features:
153
+ - Request/response capture
154
+ - Traffic modification
155
+ - Scope filtering
156
+ - Request/response callbacks
157
+
158
+ Example:
159
+ proxy = ProxyInterceptor(ProxyConfig(listen_port=8080))
160
+
161
+ @proxy.on_request
162
+ def handle_request(request):
163
+ print(f"Request: {request.method} {request.url}")
164
+
165
+ await proxy.start()
166
+ # Configure browser to use proxy at 127.0.0.1:8080
167
+ # ...
168
+ await proxy.stop()
169
+ """
170
+
171
+ def __init__(self, config: Optional[ProxyConfig] = None):
172
+ if not MITMPROXY_AVAILABLE:
173
+ raise ImportError("mitmproxy is required. Install with: pip install mitmproxy")
174
+
175
+ self.config = config or ProxyConfig()
176
+ self._requests: dict[str, InterceptedRequest] = {}
177
+ self._responses: dict[str, InterceptedResponse] = {}
178
+ self._request_callbacks: list[Callable[[InterceptedRequest], Optional[InterceptedRequest]]] = []
179
+ self._response_callbacks: list[Callable[[InterceptedResponse], Optional[InterceptedResponse]]] = []
180
+ self._master = None
181
+ self._thread: Optional[threading.Thread] = None
182
+ self._running = False
183
+ self._request_count = 0
184
+
185
+ def on_request(self, callback: Callable[[InterceptedRequest], Optional[InterceptedRequest]]):
186
+ """Register request callback (decorator)"""
187
+ self._request_callbacks.append(callback)
188
+ return callback
189
+
190
+ def on_response(self, callback: Callable[[InterceptedResponse], Optional[InterceptedResponse]]):
191
+ """Register response callback (decorator)"""
192
+ self._response_callbacks.append(callback)
193
+ return callback
194
+
195
+ async def start(self) -> bool:
196
+ """Start the proxy server"""
197
+ if self._running:
198
+ return True
199
+
200
+ try:
201
+ # Create mitmproxy options
202
+ opts = options.Options(
203
+ listen_host=self.config.listen_host,
204
+ listen_port=self.config.listen_port,
205
+ ssl_insecure=self.config.ssl_insecure,
206
+ )
207
+
208
+ # Create master
209
+ self._master = dump.DumpMaster(
210
+ opts,
211
+ with_termlog=False,
212
+ with_dumper=False,
213
+ )
214
+
215
+ # Add our addon
216
+ self._master.addons.add(self._create_addon())
217
+
218
+ # Run in thread
219
+ def run_proxy():
220
+ asyncio.set_event_loop(asyncio.new_event_loop())
221
+ self._master.run()
222
+
223
+ self._thread = threading.Thread(target=run_proxy, daemon=True)
224
+ self._thread.start()
225
+ self._running = True
226
+
227
+ logger.info(f"Proxy started on {self.config.listen_host}:{self.config.listen_port}")
228
+ return True
229
+
230
+ except Exception as e:
231
+ logger.error(f"Failed to start proxy: {e}")
232
+ return False
233
+
234
+ async def stop(self) -> None:
235
+ """Stop the proxy server"""
236
+ if self._master:
237
+ self._master.shutdown()
238
+ self._running = False
239
+ logger.info("Proxy stopped")
240
+
241
+ def _create_addon(self) -> Any:
242
+ """Create mitmproxy addon"""
243
+ interceptor = self
244
+
245
+ class AIPTAddon:
246
+ def request(self, flow: http.HTTPFlow) -> None:
247
+ # Check scope
248
+ if not interceptor._in_scope(flow.request.host):
249
+ return
250
+
251
+ interceptor._request_count += 1
252
+ request_id = f"req_{interceptor._request_count}"
253
+
254
+ # Create intercepted request
255
+ req = InterceptedRequest(
256
+ id=request_id,
257
+ timestamp=datetime.utcnow(),
258
+ method=flow.request.method,
259
+ url=flow.request.url,
260
+ host=flow.request.host,
261
+ path=flow.request.path,
262
+ headers=dict(flow.request.headers),
263
+ body=flow.request.content or b"",
264
+ )
265
+
266
+ # Parse content type
267
+ content_type = flow.request.headers.get("content-type", "")
268
+ req.content_type = content_type
269
+ req.is_json = "application/json" in content_type
270
+ req.is_form = "application/x-www-form-urlencoded" in content_type
271
+ req.is_multipart = "multipart/form-data" in content_type
272
+
273
+ # Parse cookies
274
+ if "cookie" in flow.request.headers:
275
+ for cookie in flow.request.headers["cookie"].split(";"):
276
+ if "=" in cookie:
277
+ name, value = cookie.strip().split("=", 1)
278
+ req.cookies[name] = value
279
+
280
+ # Store and notify
281
+ interceptor._requests[request_id] = req
282
+ flow.metadata["aipt_request_id"] = request_id
283
+
284
+ # Call callbacks
285
+ for callback in interceptor._request_callbacks:
286
+ try:
287
+ modified = callback(req)
288
+ if modified:
289
+ # Apply modifications to flow
290
+ flow.request.headers = http.Headers([(k, v) for k, v in modified.headers.items()])
291
+ if modified.body:
292
+ flow.request.content = modified.body
293
+ except Exception as e:
294
+ logger.error(f"Request callback error: {e}")
295
+
296
+ # Apply configured modifications
297
+ for header, value in interceptor.config.inject_headers.items():
298
+ flow.request.headers[header] = value
299
+ for header in interceptor.config.remove_headers:
300
+ if header in flow.request.headers:
301
+ del flow.request.headers[header]
302
+
303
+ def response(self, flow: http.HTTPFlow) -> None:
304
+ request_id = flow.metadata.get("aipt_request_id")
305
+ if not request_id:
306
+ return
307
+
308
+ # Get request for timing
309
+ request = interceptor._requests.get(request_id)
310
+
311
+ # Create intercepted response
312
+ resp = InterceptedResponse(
313
+ request_id=request_id,
314
+ timestamp=datetime.utcnow(),
315
+ status_code=flow.response.status_code,
316
+ reason=flow.response.reason or "",
317
+ headers=dict(flow.response.headers),
318
+ body=flow.response.content or b"",
319
+ )
320
+
321
+ # Calculate response time
322
+ if request:
323
+ resp.response_time_ms = (resp.timestamp - request.timestamp).total_seconds() * 1000
324
+
325
+ # Parse content type
326
+ content_type = flow.response.headers.get("content-type", "")
327
+ resp.content_type = content_type
328
+ resp.is_json = "application/json" in content_type
329
+ resp.is_html = "text/html" in content_type
330
+
331
+ # Store
332
+ interceptor._responses[request_id] = resp
333
+
334
+ # Call callbacks
335
+ for callback in interceptor._response_callbacks:
336
+ try:
337
+ modified = callback(resp)
338
+ if modified:
339
+ flow.response.headers = http.Headers([(k, v) for k, v in modified.headers.items()])
340
+ if modified.body:
341
+ flow.response.content = modified.body
342
+ except Exception as e:
343
+ logger.error(f"Response callback error: {e}")
344
+
345
+ return AIPTAddon()
346
+
347
+ def _in_scope(self, host: str) -> bool:
348
+ """Check if host is in scope"""
349
+ # Check excludes
350
+ for pattern in self.config.exclude_hosts:
351
+ if self._host_matches(host, pattern):
352
+ return False
353
+
354
+ # If includes specified, host must match
355
+ if self.config.include_hosts:
356
+ for pattern in self.config.include_hosts:
357
+ if self._host_matches(host, pattern):
358
+ return True
359
+ return False
360
+
361
+ return True
362
+
363
+ def _host_matches(self, host: str, pattern: str) -> bool:
364
+ """Check if host matches pattern"""
365
+ if pattern.startswith("*."):
366
+ return host.endswith(pattern[1:]) or host == pattern[2:]
367
+ return host == pattern
368
+
369
+ def get_requests(self) -> list[InterceptedRequest]:
370
+ """Get all captured requests"""
371
+ return list(self._requests.values())
372
+
373
+ def get_responses(self) -> list[InterceptedResponse]:
374
+ """Get all captured responses"""
375
+ return list(self._responses.values())
376
+
377
+ def get_request(self, request_id: str) -> Optional[InterceptedRequest]:
378
+ """Get specific request by ID"""
379
+ return self._requests.get(request_id)
380
+
381
+ def get_response(self, request_id: str) -> Optional[InterceptedResponse]:
382
+ """Get response for a request"""
383
+ return self._responses.get(request_id)
384
+
385
+ def clear_history(self) -> None:
386
+ """Clear captured traffic"""
387
+ self._requests.clear()
388
+ self._responses.clear()
389
+
390
+ def export_har(self, filepath: str) -> bool:
391
+ """Export traffic to HAR format"""
392
+ try:
393
+ har = {
394
+ "log": {
395
+ "version": "1.2",
396
+ "creator": {"name": "AIPT", "version": "2.0"},
397
+ "entries": [],
398
+ }
399
+ }
400
+
401
+ for req_id, request in self._requests.items():
402
+ response = self._responses.get(req_id)
403
+
404
+ entry = {
405
+ "startedDateTime": request.timestamp.isoformat(),
406
+ "request": {
407
+ "method": request.method,
408
+ "url": request.url,
409
+ "headers": [{"name": k, "value": v} for k, v in request.headers.items()],
410
+ "queryString": [],
411
+ "bodySize": len(request.body),
412
+ },
413
+ }
414
+
415
+ if response:
416
+ entry["response"] = {
417
+ "status": response.status_code,
418
+ "statusText": response.reason,
419
+ "headers": [{"name": k, "value": v} for k, v in response.headers.items()],
420
+ "content": {
421
+ "size": len(response.body),
422
+ "mimeType": response.content_type,
423
+ },
424
+ }
425
+ entry["time"] = response.response_time_ms
426
+
427
+ har["log"]["entries"].append(entry)
428
+
429
+ with open(filepath, "w") as f:
430
+ json.dump(har, f, indent=2)
431
+
432
+ return True
433
+ except Exception as e:
434
+ logger.error(f"HAR export error: {e}")
435
+ return False
436
+
437
+ @property
438
+ def is_running(self) -> bool:
439
+ return self._running
440
+
441
+ @property
442
+ def request_count(self) -> int:
443
+ return self._request_count
444
+
445
+
446
+ # Convenience function for simple proxy usage
447
+ def create_proxy(port: int = 8080, hosts: Optional[list[str]] = None) -> ProxyInterceptor:
448
+ """Create a configured proxy"""
449
+ config = ProxyConfig(listen_port=port)
450
+ if hosts:
451
+ config.include_hosts = hosts
452
+ return ProxyInterceptor(config)
@@ -0,0 +1,44 @@
1
+ """
2
+ AIPT Recon Module
3
+
4
+ Reconnaissance and information gathering:
5
+ - Subdomain enumeration
6
+ - Port scanning
7
+ - Technology detection
8
+ - DNS analysis
9
+ - Whois lookups
10
+ """
11
+
12
+ from .subdomain import (
13
+ SubdomainEnumerator,
14
+ SubdomainConfig,
15
+ SubdomainResult,
16
+ )
17
+ from .tech_detect import (
18
+ TechDetector,
19
+ Technology,
20
+ TechStack,
21
+ )
22
+ from .dns import (
23
+ DNSAnalyzer,
24
+ DNSRecord,
25
+ DNSResult,
26
+ )
27
+ from .osint import (
28
+ OSINTCollector,
29
+ OSINTResult,
30
+ )
31
+
32
+ __all__ = [
33
+ "SubdomainEnumerator",
34
+ "SubdomainConfig",
35
+ "SubdomainResult",
36
+ "TechDetector",
37
+ "Technology",
38
+ "TechStack",
39
+ "DNSAnalyzer",
40
+ "DNSRecord",
41
+ "DNSResult",
42
+ "OSINTCollector",
43
+ "OSINTResult",
44
+ ]