"""Report Generator for Bug Bounty Hunter MCP"""
import json
from datetime import datetime
from typing import Dict, List, Optional
from pathlib import Path
import os
class Reporter:
"""Generate professional bug bounty reports"""
def __init__(self, output_dir: str = "./results"):
"""
Initialize Reporter
Args:
output_dir: Output directory for reports
"""
self.output_dir = output_dir
Path(output_dir).mkdir(parents=True, exist_ok=True)
def generate_markdown_report(
self,
results: Dict,
title: str = "Bug Bounty Report"
) -> str:
"""
Generate Markdown report
Args:
results: Scan results
title: Report title
Returns:
Markdown content
"""
md = f"# {title}\n\n"
md += f"**Date:** {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}\n\n"
md += "---\n\n"
# Executive Summary
md += "## Executive Summary\n\n"
md += self._generate_summary(results)
md += "\n\n---\n\n"
# Findings
md += "## Findings\n\n"
if 'vulnerabilities' in results:
for i, vuln in enumerate(results['vulnerabilities'], 1):
md += self._format_vulnerability_md(i, vuln)
md += "\n---\n\n"
# Reconnaissance Data
if 'recon' in results:
md += "## Reconnaissance\n\n"
md += self._format_recon_md(results['recon'])
md += "\n"
return md
def generate_html_report(
self,
results: Dict,
title: str = "Bug Bounty Report"
) -> str:
"""
Generate HTML report
Args:
results: Scan results
title: Report title
Returns:
HTML content
"""
html = f"""
<!DOCTYPE html>
<html>
<head>
<title>{title}</title>
<style>
body {{ font-family: Arial, sans-serif; margin: 40px; }}
h1 {{ color: #333; }}
h2 {{ color: #666; border-bottom: 2px solid #ddd; padding-bottom: 5px; }}
.critical {{ color: #d32f2f; font-weight: bold; }}
.high {{ color: #f57c00; font-weight: bold; }}
.medium {{ color: #fbc02d; font-weight: bold; }}
.low {{ color: #388e3c; }}
.info {{ color: #1976d2; }}
.vulnerability {{ background: #f5f5f5; padding: 15px; margin: 10px 0; border-left: 4px solid #ddd; }}
.code {{ background: #263238; color: #aed581; padding: 10px; overflow-x: auto; }}
table {{ border-collapse: collapse; width: 100%; }}
th, td {{ border: 1px solid #ddd; padding: 8px; text-align: left; }}
th {{ background-color: #4caf50; color: white; }}
</style>
</head>
<body>
<h1>{title}</h1>
<p><strong>Generated:</strong> {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}</p>
<hr>
"""
# Add summary
html += "<h2>Executive Summary</h2>"
html += self._generate_summary_html(results)
# Add findings
if 'vulnerabilities' in results:
html += "<h2>Vulnerabilities</h2>"
for i, vuln in enumerate(results['vulnerabilities'], 1):
html += self._format_vulnerability_html(i, vuln)
html += "</body></html>"
return html
def generate_json_report(self, results: Dict) -> str:
"""
Generate JSON report
Args:
results: Scan results
Returns:
JSON string
"""
report = {
"generated": datetime.now().isoformat(),
"results": results
}
return json.dumps(report, indent=2)
def _generate_summary(self, results: Dict) -> str:
"""Generate text summary"""
summary = ""
if 'vulnerabilities' in results:
vulns = results['vulnerabilities']
summary += f"Total Vulnerabilities Found: **{len(vulns)}**\n\n"
# Count by severity
severity_count = {}
for vuln in vulns:
sev = vuln.get('severity', 'unknown')
severity_count[sev] = severity_count.get(sev, 0) + 1
for severity, count in sorted(severity_count.items()):
summary += f"- **{severity.capitalize()}:** {count}\n"
return summary
def _generate_summary_html(self, results: Dict) -> str:
"""Generate HTML summary"""
html = "<div class='summary'>"
if 'vulnerabilities' in results:
vulns = results['vulnerabilities']
html += f"<p><strong>Total Vulnerabilities:</strong> {len(vulns)}</p>"
# Count by severity
severity_count = {}
for vuln in vulns:
sev = vuln.get('severity', 'unknown')
severity_count[sev] = severity_count.get(sev, 0) + 1
html += "<ul>"
for severity, count in sorted(severity_count.items()):
html += f"<li class='{severity}'>{severity.capitalize()}: {count}</li>"
html += "</ul>"
html += "</div>"
return html
def _format_vulnerability_md(self, index: int, vuln: Dict) -> str:
"""Format vulnerability in Markdown"""
md = f"### {index}. {vuln.get('title', 'Vulnerability')}\n\n"
md += f"**Severity:** {vuln.get('severity', 'unknown').upper()}\n\n"
md += f"**URL:** `{vuln.get('url', 'N/A')}`\n\n"
if 'description' in vuln:
md += f"**Description:**\n{vuln['description']}\n\n"
if 'payload' in vuln:
md += f"**Payload:**\n```\n{vuln['payload']}\n```\n\n"
if 'remediation' in vuln:
md += f"**Remediation:**\n{vuln['remediation']}\n\n"
return md
def _format_vulnerability_html(self, index: int, vuln: Dict) -> str:
"""Format vulnerability in HTML"""
severity = vuln.get('severity', 'unknown')
html = f"<div class='vulnerability'>"
html += f"<h3 class='{severity}'>{index}. {vuln.get('title', 'Vulnerability')}</h3>"
html += f"<p><strong>Severity:</strong> <span class='{severity}'>{severity.upper()}</span></p>"
html += f"<p><strong>URL:</strong> <code>{vuln.get('url', 'N/A')}</code></p>"
if 'description' in vuln:
html += f"<p><strong>Description:</strong></p><p>{vuln['description']}</p>"
if 'payload' in vuln:
html += f"<p><strong>Payload:</strong></p><pre class='code'>{vuln['payload']}</pre>"
html += "</div>"
return html
def _format_recon_md(self, recon: Dict) -> str:
"""Format reconnaissance data in Markdown"""
md = ""
if 'subdomains' in recon:
md += f"### Subdomains ({len(recon['subdomains'])})\n\n"
for subdomain in recon['subdomains'][:20]: # Show first 20
md += f"- {subdomain}\n"
if len(recon['subdomains']) > 20:
md += f"\n*... and {len(recon['subdomains']) - 20} more*\n"
md += "\n"
if 'ports' in recon:
md += f"### Open Ports ({len(recon['ports'])})\n\n"
for port in recon['ports'][:20]:
md += f"- {port}\n"
md += "\n"
return md
def save_report(
self,
content: str,
filename: str,
format: str = "markdown"
) -> str:
"""
Save report to file
Args:
content: Report content
filename: Output filename
format: Report format
Returns:
Path to saved file
"""
filepath = os.path.join(self.output_dir, filename)
with open(filepath, 'w') as f:
f.write(content)
return filepath
async def generate_bug_bounty_report(
results: Dict,
format: str = "markdown",
output_file: str = ""
) -> Dict:
"""
Generate bug bounty report
Args:
results: Scan results
format: Report format (markdown, html, json)
output_file: Output file path
Returns:
Dictionary with report info
"""
reporter = Reporter()
if format == "markdown":
content = reporter.generate_markdown_report(results)
if not output_file:
output_file = f"report_{datetime.now().strftime('%Y%m%d_%H%M%S')}.md"
elif format == "html":
content = reporter.generate_html_report(results)
if not output_file:
output_file = f"report_{datetime.now().strftime('%Y%m%d_%H%M%S')}.html"
elif format == "json":
content = reporter.generate_json_report(results)
if not output_file:
output_file = f"report_{datetime.now().strftime('%Y%m%d_%H%M%S')}.json"
else:
return {"error": f"Unsupported format: {format}"}
filepath = reporter.save_report(content, output_file, format)
return {
"success": True,
"format": format,
"filepath": filepath,
"size": len(content),
"vulnerabilities": len(results.get('vulnerabilities', [])),
"timestamp": datetime.now().isoformat()
}