Política de nombres de fichero de Docuten eArchiving v1

Docuten eArchiving Filename Policy v1

Metadato Valor
Versión / Version v1
Estado / Status Vigente desde la fase 06.5 para todo AIP nuevo creado por POST /api/v1/ingest/file
URI del perfil / Profile URI https://docs.docuten.com/earchiving/filename-policy/v1
Dónde se cita / Where it is cited El nombre resultante es el aipPath de cada fichero dentro de premis.xml, de las hojas del sello #1 y de la atestación; el nombre declarado (originalNameNfc) se sella como originalName
Implementación / Implementation FilenamePolicy (derive, collisionKey), FileEntry, SipBuilderService, en earchiving-ingest/.../ingest/service/
Decisiones / Decisions D-07, D-08, D-09 (06.5-CONTEXT.md)
Fecha / Date 2026-11-02

1. Propósito / Purpose

Este documento define la regla cerrada y versionada con la que /file convierte el nombre que declara el cliente en el nombre que lleva el fichero dentro del paquete. commons-ip2 2.11.2 no sanea IPFile.setRenameTo (un nombre ../evil.pdf produce una entrada ZIP fuera de data/), así que la seguridad del nombre es nuestra: FilenamePolicy es la única fuente del nombre que llega al CSIP.

La URI es un identificador, no una URL que deba resolverse.

Cambiar esta regla es una versión nueva (v2), nunca una edición: aipPath queda sellado en premis.xml, en las hojas del sello #1 y en la atestación.

This document defines the closed, versioned rule that turns the client-declared file name into the name stored in the package. commons-ip2 does not sanitise setRenameTo, so the policy is the only source of the name that reaches the CSIP. Changing the rule is a new version (v2), never an edit.


2. Principio / Principle

La política conserva tal cual un nombre seguro en NFC (Unicode, espacios y ñ incluidos) y solo deriva lo inseguro. Rechaza únicamente lo irrecuperable (§4). originalNameNfc es el último segmento del nombre declarado, en NFC: la parte de directorio que algunos clientes envían no es un nombre de fichero y no se sella. Es null si el cliente no declaró nombre.

Safe NFC names are kept as they are; only unsafe parts are derived; only the unrecoverable is rejected. originalNameNfc is the last path segment of the declared name in NFC, or null.


3. Tabla de reglas / Rule table

Las reglas se aplican en este orden. {i} es la posición del fichero en el lote.

ID Regla / Rule Entrada Salida
FN-R01 Sin nombre declarado (null o en blanco) → original-{i}; originalNameNfc = null original-0
FN-R02 Se toma el último segmento tras la última / o \, en NFC y sin espacios de los extremos; ese segmento es originalNameNfc. Si queda vacío → FN-R01 C:\Users\x\factura.pdf factura.pdf
FN-R03 Rechazo de lo irrecuperable (§4), sobre TODO el nombre declarado a\u0007b.pdf rechazado
FN-R04 Segmento . o .. → original-{i} (originalNameNfc conserva el declarado) .. original-0
FN-R05 Cada carácter de < > : " \| ? * se sustituye por _ (originalNameNfc los conserva) a:b*c?.pdf a_b_c_.pdf
FN-R06 Se quitan puntos y espacios finales; si queda vacío → fallback FN-R09 a.pdf. a.pdf
FN-R07 Nombre reservado de Windows (parte anterior al primer . igual, sin distinguir mayúsculas, a CON, PRN, AUX, NUL, COM1–COM9, LPT1–LPT9) → se antepone _ con.pdf _con.pdf
FN-R08 Si el nombre excede 255 bytes UTF-8: se trunca el stem en frontera de code point preservando la extensión (desde la última ., máximo 16 bytes); si la extensión sola no cabe o deja el stem vacío → fallback FN-R09 nombre de 300 bytes .pdf ≤ 255 bytes, termina en .pdf
FN-R09 Fallback: original-{i} más . y la extensión del declarado solo si casa con [A-Za-z0-9]{1,16}; sin extensión en otro caso ... original-0

Ejemplos que se conservan tal cual / kept as they are: Factura Ñ ñ.pdf, a+b c.pdf, 100%.pdf. Un nombre en NFD (résumé.pdf) se devuelve en NFC.

Efecto de FN-R02 sobre rutas hostiles / Hostile paths: ../evil.pdf → evil.pdf; a\b.pdf → b.pdf.


4. Motivos de rechazo / Rejection reasons

Un nombre declarado se rechaza (no se falsifica) si:

Motivo Condición
CONTROL_CHARACTERS contiene un carácter de control Cc (U+0000–U+001F, U+007F–U+009F), un carácter de formato Cf (entre otros, los de dirección bidi U+202A–U+202E y U+2066–U+2069, U+200E/U+200F, U+200B–U+200D, U+FEFF, U+00AD) o un separador de línea o párrafo Zl/Zp (U+2028, U+2029)
INVALID_UNICODE contiene un surrogate desparejado, U+FFFE o U+FFFF (no representables en XML 1.0)
DECLARED_NAME_TOO_LONG el nombre declarado excede 1024 bytes UTF-8

Los caracteres Cf y Zl/Zp se rechazan porque son invisibles o reordenan lo que se muestra: un nombre como Factura\u202Efdp.exe se vería como Facturaexe.pdf en el sello, en originalName y en el catálogo, y U+2028/U+2029 parten líneas en los visores de logs. Consecuencia asumida: U+200C/U+200D (ZWNJ/ZWJ), necesarios en algunas escrituras (p. ej. persa o secuencias emoji), también se rechazan; los signos combinantes (Mn/Mc) y las letras acentuadas siguen admitidos. La regla se cerró en v1 antes de que existiera ninguna instancia sellada.

A name with characters not representable in XML 1.0 is not falsified in PREMIS: it is rejected. So are format characters (Cf: bidi overrides/isolates, zero-width characters, BOM, soft hyphen) and line/paragraph separators (Zl, Zp): they spoof the displayed name or split log lines.


5. Clave de colisión / Collision key

FilenamePolicy.collisionKey(finalName) = NFC y después toUpperCase(Locale.ROOT).toLowerCase(Locale.ROOT) (casefold aproximado, D-09). Dos ficheros del mismo lote cuyas claves coinciden colisionan. Límite conocido: ß/ẞ y la sigma final no son un casefold Unicode completo; se acepta como supuesto de baja probabilidad (no se añade ICU4J).


6. Versionado / Versioning

La versión de la regla es v1 (FilenamePolicy.RULE_VERSION) y un test (FilenamePolicyTest) fija la paridad entre este documento y el código: IDs FN-R01..FN-R09, versión y URI. Cualquier cambio de comportamiento es una versión nueva (v2, URI nueva), nunca una edición de esta.