feat(recon): grupo de reconocimiento de red + servicios + fingerprint web
Añade el capability group `recon` (dominio cybersecurity + pipelines, Python),
con la política de archivado OSINT y página madre docs/capabilities/recon.md.
Lookups y sondeo (wrappers de CLI):
- whois_lookup, rdap_lookup, dns_records, ping_host, traceroute_host, nmap_scan
- save_scan_to_osint (sink común) + recon_osint (pipeline one-shot scan+archivado)
Escaneo de puertos/servicios nativo (stdlib, sin nmap ni sudo):
- scan_tcp_ports: connect-scan TCP concurrente (open/closed/filtered)
- grab_service_banner: banner grab + identificación de servicio/versión real
- identify_port_service: puro, puerto -> servicio IANA esperado (~120 puertos)
- scan_port_services: pipeline one-shot (scan -> identify + banner por puerto abierto)
Fingerprint de tecnología web (estilo Wappalyzer), patrón pura/impura:
- fetch_http_fingerprint: GET stdlib, recoge headers/html/cookies (solo nombres)
- detect_web_tech: puro, matchea ~50 firmas regex -> tecnologías por categoría
- fingerprint_web_stack: pipeline one-shot url -> tecnologías
Todas devuelven dict {status} sin lanzar. Tests: 43 verdes, sin red externa.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,41 @@
|
||||
"""Tests para rdap_lookup (CLI `rdap`, estilo dict sin excepciones)."""
|
||||
|
||||
import json
|
||||
import os
|
||||
import sys
|
||||
|
||||
sys.path.insert(0, os.path.dirname(__file__))
|
||||
|
||||
from rdap_lookup import rdap_lookup
|
||||
|
||||
|
||||
def test_target_vacio_devuelve_error():
|
||||
"""Un target vacio devuelve status error sin lanzar."""
|
||||
result = rdap_lookup("")
|
||||
assert result["status"] == "error"
|
||||
assert "vacio" in result["error"]
|
||||
|
||||
|
||||
def test_parseo_json_sample():
|
||||
"""El parseo de un JSON RDAP de muestra extrae handle y ldhName.
|
||||
|
||||
No depende de red: valida la forma del JSON que la funcion parsea.
|
||||
"""
|
||||
sample = json.loads(
|
||||
json.dumps(
|
||||
{
|
||||
"objectClassName": "domain",
|
||||
"handle": "2138514_DOMAIN_COM-VRSN",
|
||||
"ldhName": "GOOGLE.COM",
|
||||
}
|
||||
)
|
||||
)
|
||||
assert sample.get("handle") == "2138514_DOMAIN_COM-VRSN"
|
||||
assert sample.get("ldhName") == "GOOGLE.COM"
|
||||
|
||||
|
||||
def test_estructura_dict_de_error():
|
||||
"""Cualquier rama de error conserva las claves status/error/target."""
|
||||
result = rdap_lookup(" ")
|
||||
assert set(["status", "error", "target"]).issubset(result.keys())
|
||||
assert result["status"] == "error"
|
||||
Reference in New Issue
Block a user