"""Orquestador OSINT pasivo: genera candidatos de enriquecimiento de una persona. Compone funciones atomicas del registro (`guess_email_formats`, `enumerate_username_sites`, `build_search_dorks`) para producir candidatos OSINT de una persona SIN contactar ni atacar al objetivo. Los dorks se generan pero NO se ejecutan. Funcion IMPURA: `enumerate_username_sites` consulta servicios publicos (red). """ from cybersecurity import ( build_search_dorks, enumerate_username_sites, guess_email_formats, ) # Dominios de correo comunes usados cuando el caller no aporta dominios propios. _COMMON_EMAIL_DOMAINS = ("gmail.com", "outlook.com") def enrich_person_passive( nombre: str, apellidos: str, dominios: list | None = None, usernames: list | None = None, ) -> dict: """Genera candidatos OSINT pasivos para una persona. Para cada dominio aportado (o los dominios comunes gmail/outlook si no se da ninguno) genera los formatos de email candidatos. Para cada username aportado comprueba en que sitios publicos existe. Ademas genera dorks de busqueda de tipo persona (que NO se ejecutan, solo se devuelven). Args: nombre: nombre de pila de la persona. apellidos: apellido(s) de la persona. dominios: lista de dominios de correo donde buscar formatos de email. Si es None o vacia, se usan los dominios comunes gmail/outlook. usernames: lista de usernames a comprobar en sitios publicos. Si es None o vacia, no se realiza ninguna comprobacion de username. Returns: dict con las claves: - email_candidates: lista de emails candidatos (no verificados). - username_hits: lista de resultados de enumerate_username_sites por cada username comprobado. - dorks: lista de dorks de busqueda generados (no ejecutados). Raises: ValueError: si nombre y apellidos estan ambos vacios. """ if not (nombre or "").strip() and not (apellidos or "").strip(): raise ValueError("nombre y apellidos no pueden estar ambos vacios") target_domains = [d for d in (dominios or []) if d] or list(_COMMON_EMAIL_DOMAINS) email_candidates: list = [] for dominio in target_domains: candidates = guess_email_formats(nombre, apellidos, dominio) if candidates: email_candidates.extend(candidates) # Deduplicar preservando orden. email_candidates = list(dict.fromkeys(email_candidates)) username_hits: list = [] for username in usernames or []: if not username: continue hits = enumerate_username_sites(username) username_hits.append({"username": username, "hits": hits}) target = f"{nombre} {apellidos}".strip() dorks = build_search_dorks(target, "persona") return { "email_candidates": email_candidates, "username_hits": username_hits, "dorks": dorks, }