paperless-esig
paperless-esig is a third-party parser for Paperless-ngx. It adds support for EU electronically signed documents.
Supported formats
| Format | Extensions |
|---|---|
| ASiC-E containers | .edoc, .asice, .bdoc, .adoc |
| CAdES signatures | .p7m |
| PAdES-signed PDFs | .pdf |
Paperless-ngx does not consume these files by default. The parser is required for them.
Why Paperless-ngx cannot handle these files
ASiC-E containers are ZIP archives. libmagic reports them as application/zip, and Paperless-ngx rejects the MIME type. CAdES files are reported as application/octet-stream and are also rejected. PAdES-signed PDFs are consumed, but the built-in parser does not expose their signature metadata.
Signature formats in detail
XAdES
Used inside ETSI ASiC-E containers (.edoc, .asice, .bdoc, .adoc). The parser extracts the signing time, signer certificate, certificate chain, RFC 3161 timestamp, and OCSP values. It verifies the document digest, the SignedProperties digest, and the signature value offline.
CAdES
CMS SignedData (ETSI EN 319 122) in .p7m files. The embedded PDF becomes the rendition. The CMS signing time, signer, and verification results are exposed as metadata. Detached .p7s signatures are detected but rejected during parsing with a clear error, because they carry no document.
PAdES
PDFs signed with the ETSI.CAdES.detached or adbe.pkcs7.detached subfilter. The signed PDF is the rendition. The document date prefers the CMS signing time and falls back to the signature's /M field. The covered byte range, signer, and verification results are exposed as metadata.
Encoding notes
Both DER and BER (indefinite-length) CMS encodings are accepted. Some signers, such as the adbe.pkcs7.detached flavour, emit BER. Verification is offline only. It proves that the document digest and the signature value are consistent with the signer certificate. It does not validate trust chains, revocation status, or timestamps.
What the parser does
- Stores the original file unchanged. This is required for legal compliance.
- Extracts the signed PDF as the display and archive rendition. Browsers cannot render ZIP containers. A PAdES PDF is already a rendition and keeps its signature.
- Extracts the text of the PDF for search.
- Sets the document date from the signature signing time, with fallbacks to the PAdES
/Mfield and the PDF creation date. - Displays signature metadata in the metadata tab: signer name, organisation, country, signing time, certificate chain and issuer, RFC 3161 timestamp authority, and OCSP presence.
- Verifies the document digest and the signature value offline.
- Handles nested containers (an EDOC inside an EDOC, as produced by the Latvian e-archive) and multi-document containers (multiple PDFs and office documents merged into a single rendition).
- Assigns the signer as the document's correspondent. This happens after consumption, only when no correspondent was determined by content matching or workflow rules. The signer (organisation preferred over common name) is looked up case-insensitively and created if it does not exist, and the document is re-indexed so the correspondent is searchable immediately. This is enabled by default. Disable it with
PAPERLESS_ESIG_ASSIGN_SIGNER_AS_CORRESPONDENT=false. Known limitations: the assignment is not recorded in the audit log, and the UI may show the new correspondent as "Private" until the page is reloaded.
Install
The parser runs inside Paperless-ngx. Use one of two methods.
Method 1: Docker
-
Clone this repository and build the image:
docker build -t paperless-ngx-esig .
-
In
docker-compose.yml, replace thewebserverimage with your build:services: webserver: image: paperless-ngx-esig # ...everything else stays the same
-
Restart the stack:
docker compose up -d
Method 2: Bare metal
Install the package into the same virtual environment that runs Paperless-ngx:
uv pip install paperless-esig
Verify the install
-
Start Paperless-ngx and check the logs. Look for a line like this:
[paperless.parsers.registry] [third-party] Paperless-ngx ESig Parser v0.3.0 — https://github.com/Exerra/paperless-esigIf the logs say
No third-party parsers discovered.instead, see Troubleshooting. -
Upload an
.edoc,.asice,.bdoc,.adoc, or.p7mfile, or a PAdES-signed PDF. The document is consumed, displays the inner PDF, and shows signature metadata in the metadata tab.
Limitations
- Documents are stored with the MIME type that libmagic reports. ASiC-E containers are stored as
application/zipand CAdES files asapplication/octet-stream. The original file extension (.edoc,.asice,.p7m, and so on) is preserved in the stored filename. - Plain ZIP files pass API and mail upload validation but are rejected during consumption with an "Unsupported mime type" error. The parser cannot inspect a file at validation time. ZIP files placed in the consume directory are attempted instead of silently skipped. The same applies to
application/octet-streamfiles: CAdES signatures are the only octet-stream files that are consumed. - Detached
.p7ssignatures are detected but rejected during parsing. They carry no document, so there is nothing to display or search. - Office documents (DOCX, ODT, and similar) inside a container are converted to PDF by Gotenberg, and their text is extracted by Tika, when those services are configured with
PAPERLESS_TIKA_ENDPOINT. Without them, the DOCX text is still extracted locally and the affected pages are omitted from the rendition.
Requirements
- Paperless-ngx 2.x. The parser uses the
paperless_ngx.parsersentrypoint registry. - The container must contain a PDF. Containers without a PDF cannot be ingested.
Troubleshooting
No third-party parsers discovered.in the logs. The package is not installed in the environment that Paperless-ngx runs in. For Docker, check that your compose file points at the image you built (docker images).uv: command not found. Install uv first. Alternatively,python3 -m pip install .works.- Plain ZIP files are rejected with "Unsupported mime type". This is expected. See Limitations.
License
GPL-3.0-or-later. Derived from the Paperless-ngx project, which is GPL-3.0.
For developers
Building the Docker image
The build defaults to the latest release from PyPI:
docker build -t paperless-ngx-esig .
Build a specific release:
docker build --build-arg ESIG_VERSION=0.3.0 -t paperless-ngx-esig .
Build from your local checkout, for development or unreleased changes:
docker build --build-arg ESIG_SOURCE=local -t paperless-ngx-esig .
Build against a specific Paperless-ngx base version:
docker build --build-arg PAPERLESS_VERSION=2.14.7 -t paperless-ngx-esig .
make docker and make docker-local are shortcuts for the first and third commands.
Development
Prerequisites
- uv
- Python 3.11 or newer (uv installs it for you)
- Docker, only for the Docker image targets
- A checkout of Paperless-ngx, for the test suite
Set up
git clone https://github.com/Exerra/paperless-esig.git
cd paperless-esig
uv sync
git clone --depth 1 https://github.com/paperless-ngx/paperless-ngx.git ../paperless-ngx
uv sync creates a virtual environment and installs the package plus dev dependencies (django, pytest, ruff, and others). The tests import Paperless-ngx's own code, so the checkout must be on PYTHONPATH.
Run the tests
PYTHONPATH=../paperless-ngx/src uv run pytest
make test does the same. It uses PAPERLESS_NGX_SRC, which defaults to ../paperless-ngx/src relative to this repo. Override it with make test PAPERLESS_NGX_SRC=/path/to/paperless-ngx/src.
The tests build synthetic signed containers. They do not contain real personal data. They need only the Paperless-ngx source importable. No database or running instance is required.
If the tests fail with ModuleNotFoundError: No module named 'documents', the Paperless-ngx checkout is missing or not on PYTHONPATH.
Lint
uv run ruff check src tests
Build a wheel
uv build
Artifacts land in dist/ as paperless_esig-<version>-py3-none-any.whl and paperless_esig-<version>.tar.gz.
Makefile targets
| Command | What it does |
|---|---|
make venv |
Create venv and install dev dependencies (uv sync) |
make test |
Run the test suite |
make lint |
Run ruff |
make build |
Build wheel and sdist into dist/ |
make docker |
Build the image from the latest PyPI release |
make docker-local |
Build the image from your local checkout |
make clean |
Remove build artifacts and caches |
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file paperless_esig-0.3.0.tar.gz.
File metadata
- Download URL: paperless_esig-0.3.0.tar.gz
- Upload date:
- Size: 58.9 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.12.3 {"installer":{"name":"uv","version":"0.12.3","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
bbb02462dde1bf20099f429aa0efc26f05e541bac1d6c8bc244fa711e8ee9ec1
|
|
| MD5 |
159cf4a6b1a0140493ddd9c9120908da
|
|
| BLAKE2b-256 |
f903520528ef53fef2f1ada42558deb94efecc23b2ed5433dfdc328bd237e370
|
File details
Details for the file paperless_esig-0.3.0-py3-none-any.whl.
File metadata
- Download URL: paperless_esig-0.3.0-py3-none-any.whl
- Upload date:
- Size: 36.2 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.12.3 {"installer":{"name":"uv","version":"0.12.3","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
17d0f99838c2ad57717850992ce4f52bc477c9a92501cd2274ea1fe8a76776b3
|
|
| MD5 |
12bfa0de5bf8eb129d2e8cfafbab03b5
|
|
| BLAKE2b-256 |
aa5becd0ce85d118f5e8c2f392863359ab94c6537c7ee4501291715c9a6af5fa
|