--- name: extract_pdf_metadata kind: function lang: py domain: cybersecurity version: "1.0.0" purity: impure signature: "def extract_pdf_metadata(pdf_path: str) -> dict" description: "Lee los metadatos del Document Info de un PDF con pypdf (titulo, autor, creador, productor, fechas, numero de paginas) mas el volcado completo en `raw`. OSINT pasiva sobre documentos propios: revela quien y con que software genero el documento. Tolerante a PDFs cifrados (no falla, rellena `error`)." tags: [osint-passive, pdf, metadata, document, forensics, pypdf, extract, cybersecurity, python] uses_functions: [] uses_types: [] returns: [] returns_optional: false error_type: "error_go_core" imports: [pypdf] params: - name: pdf_path desc: "ruta al archivo PDF en disco" output: "dict con title, author, creator, producer, creation_date, mod_date (ISO 8601 si parseables, sino valor crudo), num_pages, raw (todo el doc info) y error (None si todo fue bien, mensaje en caso contrario)." tested: true tests: - "PDF con metadatos devuelve titulo, autor y num_pages" - "PDF sin doc info devuelve campos None sin petar" - "fechas parseables se devuelven en ISO 8601" test_file_path: "python/functions/cybersecurity/extract_pdf_metadata_test.py" file_path: "python/functions/cybersecurity/extract_pdf_metadata.py" --- ## Ejemplo ```python import sys, os sys.path.insert(0, os.path.join("python", "functions")) from cybersecurity.extract_pdf_metadata import extract_pdf_metadata meta = extract_pdf_metadata( "/home/enmanuel/Obsidian/osint/attachments/personas/cv_objetivo.pdf" ) print(meta["author"]) # 'Enmanuel G.' (quien lo creo) print(meta["producer"]) # 'Microsoft Word 2021' (con que software) print(meta["creation_date"]) # '2024-03-11T10:22:00+01:00' print(meta["num_pages"]) # 3 ``` ## Cuando usarla Cuando recolectes inteligencia pasiva sobre un PDF propio o de un objetivo y necesites saber quien lo creo, con que herramienta y cuando. Usala tambien para auditar tus propios documentos antes de publicarlos: el campo `author` y `producer` suelen filtrar el nombre real del usuario, la version del software y la organizacion, datos que no quieres exponer. ## Gotchas - Funcion impura: abre el archivo del disco. Captura la excepcion en lugar de propagarla — si el PDF esta corrupto, cifrado o no es un PDF, devuelve el dict con lo que pudo leer y un mensaje en `error` (no lanza). - PDFs cifrados: intenta abrir con password vacio (caso comun de "restriccion de copia"). Si requiere password real, `error` empieza por `encrypted:` y los campos pueden quedar None. - Muchas fechas de PDF vienen en formato `D:YYYYMMDDHHmmSS+ZZ`; se convierten a ISO 8601 cuando pypdf las parsea, sino se devuelven crudas. - `raw` serializa los valores a string para evitar tipos no JSON-friendly (IndirectObject, ByteStringObject). Los campos normalizados conservan el contenido textual.