mirror of
https://github.com/yogeshojha/rengine.git
synced 2026-10-20 23:31:31 +02:00
The host:port -> live HTTP asset convergence. After discovery, a scan now runs expansion: - port_scan: naabu (cdn-gated, well-known service names) -> Port - cdn_check: cdncheck flags CDN/WAF/cloud IPs (ip family) - http_probe: httpx probes the host:port matrix; one pass enriches each service with status/title/tech/server/TLS/cdn/jarm/favicon/hash -> HttpAsset, with asn backfilled from the resolved IP httpx -tls-grab carries cert data inline (no separate tlsx pass); nmap is dropped — naabu for ports, httpx for HTTP service id. Also: every engine moved to its own folder; net_options() threads proxy/headers/user-agent into every tool; rengine-tools no longer installs top-level modules that shadowed libs (httpx); tool binaries resolve from the go bin ahead of venv console scripts. New Port + HttpAsset models + migration and the http_assets headline rollup.
217 lines
6.6 KiB
Python
217 lines
6.6 KiB
Python
from shared.enums.notification import NotificationSeverity, NotificationType
|
|
|
|
|
|
def whois_enrichment_complete(
|
|
success: int,
|
|
failed: int,
|
|
total: int,
|
|
) -> dict:
|
|
if failed == 0:
|
|
return {
|
|
"type": NotificationType.TARGET,
|
|
"severity": NotificationSeverity.SUCCESS,
|
|
"title": "WHOIS Enrichment Complete",
|
|
"message": (
|
|
f"WHOIS lookup completed for {success} "
|
|
f"{'target' if success == 1 else 'targets'}."
|
|
),
|
|
}
|
|
return {
|
|
"type": NotificationType.TARGET,
|
|
"severity": NotificationSeverity.WARNING,
|
|
"title": "WHOIS Enrichment Complete",
|
|
"message": (
|
|
f"WHOIS lookup completed: {success} succeeded, "
|
|
f"{failed} failed out of {total} targets."
|
|
),
|
|
}
|
|
|
|
|
|
def whois_enrichment_failed(error: str) -> dict:
|
|
return {
|
|
"type": NotificationType.TARGET,
|
|
"severity": NotificationSeverity.ERROR,
|
|
"title": "WHOIS Enrichment Failed",
|
|
"message": f"WHOIS enrichment task failed: {error}",
|
|
}
|
|
|
|
|
|
def viewdns_enrichment_complete(
|
|
success: int, failed: int, skipped: int, total: int
|
|
) -> dict:
|
|
if failed == 0 and skipped == 0:
|
|
severity = NotificationSeverity.SUCCESS
|
|
title = "ViewDNS Enrichment Complete"
|
|
message = f"Successfully enriched {success}/{total} targets with ViewDNS data."
|
|
elif success > 0:
|
|
severity = NotificationSeverity.WARNING
|
|
title = "ViewDNS Enrichment Partially Complete"
|
|
message = (
|
|
f"ViewDNS enrichment finished: {success} succeeded, "
|
|
f"{failed} failed, {skipped} skipped out of {total} targets."
|
|
)
|
|
else:
|
|
severity = NotificationSeverity.ERROR
|
|
title = "ViewDNS Enrichment Failed"
|
|
message = (
|
|
f"ViewDNS enrichment could not complete: "
|
|
f"{failed} failed, {skipped} skipped out of {total} targets."
|
|
)
|
|
|
|
return {
|
|
"type": NotificationType.TARGET,
|
|
"severity": severity,
|
|
"title": title,
|
|
"message": message,
|
|
}
|
|
|
|
|
|
def viewdns_enrichment_failed(error: str) -> dict:
|
|
return {
|
|
"type": NotificationType.TARGET,
|
|
"severity": NotificationSeverity.ERROR,
|
|
"title": "ViewDNS Enrichment Failed",
|
|
"message": f"ViewDNS enrichment task failed: {error}",
|
|
}
|
|
|
|
|
|
def ripestat_enrichment_complete(
|
|
success: int, failed: int, skipped: int, total: int
|
|
) -> dict:
|
|
if failed == 0 and skipped == 0:
|
|
severity = NotificationSeverity.SUCCESS
|
|
title = "BGP Enrichment Complete"
|
|
message = f"Successfully enriched {success} targets with BGP data."
|
|
elif success > 0:
|
|
severity = NotificationSeverity.WARNING
|
|
title = "BGP Enrichment Partially Complete"
|
|
message = (
|
|
f"BGP enrichment finished: {success} succeeded, "
|
|
f"{failed} failed, {skipped} skipped out of {total} targets."
|
|
)
|
|
else:
|
|
severity = NotificationSeverity.ERROR
|
|
title = "BGP Enrichment Failed"
|
|
message = (
|
|
f"BGP enrichment could not complete: "
|
|
f"{failed} failed, {skipped} skipped out of {total} targets."
|
|
)
|
|
|
|
return {
|
|
"type": NotificationType.TARGET,
|
|
"severity": severity,
|
|
"title": title,
|
|
"message": message,
|
|
}
|
|
|
|
|
|
def ripestat_enrichment_failed(error: str) -> dict:
|
|
return {
|
|
"type": NotificationType.TARGET,
|
|
"severity": NotificationSeverity.ERROR,
|
|
"title": "BGP Enrichment Failed",
|
|
"message": f"BGP enrichment task failed: {error}",
|
|
}
|
|
|
|
|
|
_SECONDS_PER_MINUTE = 60
|
|
_MINUTES_PER_HOUR = 60
|
|
|
|
|
|
def _scan_meta(scan_id: str) -> dict:
|
|
return {"scan_id": str(scan_id), "url": f"/scans/{scan_id}"}
|
|
|
|
|
|
def _scan_duration(seconds: float | None) -> str:
|
|
if not seconds or seconds < 0:
|
|
return ""
|
|
seconds = int(seconds)
|
|
if seconds < _SECONDS_PER_MINUTE:
|
|
return f" in {seconds}s"
|
|
minutes, rem = divmod(seconds, _SECONDS_PER_MINUTE)
|
|
if minutes < _MINUTES_PER_HOUR:
|
|
return f" in {minutes}m {rem}s" if rem else f" in {minutes}m"
|
|
hours, minutes = divmod(minutes, _MINUTES_PER_HOUR)
|
|
return f" in {hours}h {minutes}m"
|
|
|
|
|
|
def scan_started(scan_id: str, target: str, engine: str) -> dict:
|
|
return {
|
|
"type": NotificationType.SCAN,
|
|
"severity": NotificationSeverity.INFO,
|
|
"title": "Scan Started",
|
|
"message": f"Scan of {target} started with engine {engine}.",
|
|
"metadata": _scan_meta(scan_id),
|
|
}
|
|
|
|
|
|
_SCAN_COUNT_LABELS = {
|
|
"subdomains_found": ("subdomain", "subdomains"),
|
|
"ips_found": ("IP", "IPs"),
|
|
"open_ports_found": ("open port", "open ports"),
|
|
"http_assets_found": ("HTTP service", "HTTP services"),
|
|
"vulnerabilities_found": ("vulnerability", "vulnerabilities"),
|
|
"endpoints_found": ("endpoint", "endpoints"),
|
|
}
|
|
|
|
|
|
def scan_count_summary(counts: dict) -> str:
|
|
parts = [
|
|
f"{n} {singular if n == 1 else plural}"
|
|
for col, (singular, plural) in _SCAN_COUNT_LABELS.items()
|
|
if (n := counts.get(col, 0))
|
|
]
|
|
return ", ".join(parts) if parts else "no assets"
|
|
|
|
|
|
def scan_completed(
|
|
scan_id: str,
|
|
target: str,
|
|
engine: str,
|
|
counts: dict,
|
|
duration_seconds: float | None,
|
|
) -> dict:
|
|
return {
|
|
"type": NotificationType.SCAN,
|
|
"severity": NotificationSeverity.SUCCESS,
|
|
"title": "Scan Completed",
|
|
"message": (
|
|
f"Scan of {target} ({engine}) completed"
|
|
f"{_scan_duration(duration_seconds)} — {scan_count_summary(counts)}."
|
|
),
|
|
"metadata": _scan_meta(scan_id),
|
|
}
|
|
|
|
|
|
def scan_new_subdomains(scan_id: str, target: str, count: int) -> dict:
|
|
return {
|
|
"type": NotificationType.SCAN,
|
|
"severity": NotificationSeverity.INFO,
|
|
"title": "New Subdomains Discovered",
|
|
"message": (
|
|
f"{count} new {'subdomain' if count == 1 else 'subdomains'} "
|
|
f"discovered on {target}."
|
|
),
|
|
"metadata": _scan_meta(scan_id),
|
|
}
|
|
|
|
|
|
def scan_failed(scan_id: str, target: str, engine: str, error: str) -> dict:
|
|
return {
|
|
"type": NotificationType.SCAN,
|
|
"severity": NotificationSeverity.ERROR,
|
|
"title": "Scan Failed",
|
|
"message": f"Scan of {target} ({engine}) failed: {error[:300]}",
|
|
"metadata": _scan_meta(scan_id),
|
|
}
|
|
|
|
|
|
def scan_cancelled(scan_id: str, target: str, engine: str) -> dict:
|
|
return {
|
|
"type": NotificationType.SCAN,
|
|
"severity": NotificationSeverity.WARNING,
|
|
"title": "Scan Cancelled",
|
|
"message": f"Scan of {target} ({engine}) was cancelled.",
|
|
"metadata": _scan_meta(scan_id),
|
|
}
|