Files
rengine/api/pyproject.toml
T
Yogesh OjhaandClaude Opus 5 0522444245 feat(reports): white-labelling, and a renderer that cannot be made to fetch
Uploaded typefaces and instance-wide branding defaults, which together make a
report genuinely white-labellable: a client's own font, a logo set once, and a
theme that names both.

The security half came first, because the logo field was a live SSRF. It was a
free-text string rendered into an <img src>, and WeasyPrint would have fetched
whatever it pointed at from inside the worker. Nothing fetches now, at four
layers. The load-bearing one is a WeasyPrint url_fetcher that allows data: URIs
and files under three known roots and refuses everything else; it was checked
against cloud metadata, internal https, loopback, /etc/passwd, a UNC host, ftp
and protocol-relative references. Above it sit three input guards: a logo must
be embedded data of a known image type, an uploaded theme may not use @import or
a url() that is not data:, and authored markdown loses any image that is not
embedded. A new feature that lets a report name a resource goes through the
fetcher, not around it.

A typeface is bytes, never a link. The family row records files named by us, so
a hostile filename never reaches disk, and the family directory refuses anything
resolving outside itself. A face is accepted only when the bytes agree: the
signature is sniffed and then fontTools opens it and requires outlines, which is
why fonttools is now an api dependency rather than only a WeasyPrint one. A
5-byte file with a valid TTF header and a 4 KB file of padding are both refused.
The family name is banned from carrying quotes or braces because it is written
into a quoted CSS font-family string.

The standalone HTML export now embeds only the families the theme actually
names, which halves it, and no longer carries file:// references that would have
been dead outside the container.

Instance defaults fill only what a template leaves blank, so setting a logo once
never overrides a per-client deliverable that set its own.

Verified: a real TTF family uploaded and embedded in a 53-page PDF under an
uploaded theme with an uploaded logo, and every probe above refused.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017f2Mf2HGwFaTRnui4UxpRd
2026-09-06 12:53:18 +05:30

33 lines
789 B
TOML

[project]
name = "rengine-api"
version = "3.0.0"
description = "reNgine: FastAPI backend"
requires-python = ">=3.13"
dependencies = [
"alembic>=1.18.3",
"anthropic>=0.69.0",
"apprise>=1.9.0",
"argon2-cffi>=25.1.0",
"asyncpg>=0.31.0",
"brotli>=1.1.0",
"fonttools>=4.59.2",
"celery>=5.6.2",
"cryptography>=42",
"fastapi>=0.128.0",
"fastapi-pagination>=0.15.8",
"passlib[bcrypt]>=1.7.4",
"pydantic-settings>=2.12.0",
"pyotp>=2.9.0",
"python-jose>=3.5.0",
"python-multipart>=0.0.22",
"qrcode[pil]>=7.4.2",
"redis>=7.1.0",
"sqlmodel>=0.0.31",
"uvicorn>=0.40.0",
"validators>=0.35.0",
"pyyaml>=6.0",
"zxcvbn>=4.5.0",
"rengine-shared @ file:///app/shared",
"rengine-tools @ file:///app/tools",
]