Skip to content

Migrate backend from Flask to Express + add security hardening - #1

Merged
Francy2009 merged 3 commits into
mainfrom
claude/app-status-check-cbvu4b
Aug 9, 2026
Merged

Francy2009 merged 3 commits into
mainfrom
claude/app-status-check-cbvu4b

Conversation

@Francy2009

Copy link
Copy Markdown
Owner

Summary

This PR replaces the Flask backend with a Node.js/Express server and implements comprehensive security hardening for the LaTeX compiler. The application now runs on a single Node.js process instead of Python, with all file I/O moved to system temp directories. Critical XSS vulnerabilities in HTML generation have been fixed through systematic HTML escaping and a complete LaTeX-to-HTML parser rewrite.

Key Changes

Backend Migration

  • Replaced Flask with Express.js — server.js now handles all routing, file uploads, and compilation orchestration
  • Moved working directories to system temp — All compilation output now writes to os.tmpdir()/texforge instead of backend/static and backend/compiled, making the project directory read-only (required for serverless platforms like Vercel)
  • Output delivery via response body — PDF and HTML are now returned as base64-encoded data in the JSON response instead of being saved to disk with public URLs, eliminating file enumeration attacks
  • Added multer for file uploads — Replaces Flask's file handling with proper multipart form parsing and size limits

Security Hardening

  • XSS prevention — Implemented escapeHtml() function and complete LaTeX text rendering pipeline (renderLatexText(), mathToHtml()) that safely converts LaTeX to HTML with proper escaping of all user-controlled content
  • Removed static file serving — /static route no longer exists; outputs don't persist on server
  • Isolated preview in sandbox iframe — HTML preview runs in sandbox="allow-scripts" iframe with opaque origin
  • Removed external CDN dependencies — MathJax no longer loaded from cdn.jsdelivr.net; math rendering now done server-side with Unicode symbols
  • Added security headers — Content-Security-Policy, X-Content-Type-Options, X-Frame-Options, Referrer-Policy, Cross-Origin-Opener-Policy, Permissions-Policy
  • Rate limiting on /compile — 12 requests per minute per IP

LaTeX Rendering

  • Comprehensive symbol tables — Added GREEK, SYMBOLS, BIG_OPERATORS, MATH_FUNCTIONS mappings for Unicode math rendering
  • Fraction and radical support — \frac, \sqrt now render as proper HTML structures with CSS classes
  • Text styling in math mode — \text, \mathbf, \mathit, etc. properly handled
  • Superscript/subscript — ^ and _ convert to <sup> and <sub> with Unicode characters
  • ASCII fallback for PDF — ASCII_MATH table provides ASCII approximations when Unicode symbols can't be embedded in PDF

Documentation & Pages

  • Added /docs/ documentation site — Comprehensive guide to quizstruct.sty, question types, and compilation flow
  • Added legal pages — /privacy and /termini (terms of service) with proper placeholders for contact info
  • Updated frontend — New index.html with improved UI, preview panel with sandbox isolation, template buttons

Deployment

  • Docker support — Dockerfile with Node 22 + TeX Live + tex4ht, docker-compose.yml for production stack
  • Vercel serverless — api/index.js and vercel.json for deployment on Vercel (uses /tmp for temp files)
  • Environment configuration — PORT now configurable via process.env.PORT

Testing & CI

  • Updated GitHub Actions — New ci.yml workflow tests Node server startup, frontend serving, API endpoints, and compilation with actual .tex files
  • Removed old test artifacts — Deleted test_*.json and test_*.pdf files

Implementation Details

  • Stateless compilation — Each request creates a temporary working directory, compiles, extracts outputs, and deletes everything before responding
  • Fallback JS compiler — Server can generate PDF via pdf-lib and HTML via internal parser even without TeX Live installed
  • Font support — Added fontkit for custom font handling in

https://claude.ai/code/session_01FRwidp8pte45RXaecqJaAe

claude added 3 commits August 9, 2026 09:50
The project runs on Node/Express but .gitignore only covered Python,
so node_modules/ showed up as untracked after a dependency install.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FRwidp8pte45RXaecqJaAe
…ck Node

La regola *.html in .gitignore, pensata per gli output di htlatex, escludeva
anche frontend/index.html e docs/index.html: da un clone pulito il server
partiva ma la homepage rispondeva 404. Documentazione, CI e deploy inoltre
descrivevano ancora un backend Flask sostituito da Express.

Frontend
- ricrea frontend/index.html sugli id attesi da app.js (dropzone, fileInput,
  fileList, compileBtn/.run-label, outputs, pdfCard, htmlCard, log, logStatus)
- aggiunge docs/index.html con gli elementi richiesti da docs/script.js
- restringe la regola .gitignore a latex-source/*.html ed esempi/*.html
- corregge la lista ASSETS del service worker: precacheava /script.js (che nel
  frontend non e' il file dell'app) e /, quindi addAll falliva in blocco e la
  modalita' offline non funzionava; esclude /api dalla cache

CI e deploy
- riscrive ci.yml per Node: smoke test su frontend, docs, API, compilazione
  singola e multipla; job separato per la compilazione LaTeX reale
- aggiunge Dockerfile (Node 22 + TeX Live, utente non-root, healthcheck),
  docker-compose.yml e .dockerignore, richiesti da deploy-vps.sh
- allinea la porta del proxy nginx da 5000 a 3000
- release.yml pubblicava esempi/quiz.tex, che sta in latex-source/

Altro
- quizstruct.sty usa itemize[label=...] senza dichiarare enumitem: funzionava
  solo perche' ogni esempio lo importava a mano
- server.js rispetta la variabile d'ambiente PORT
- rimuove da metadata.json la capability Gemini, che il codice non usa
- aggiorna README e CONTRIBUTING allo stack reale, documenta le API
- elimina file di scarto: un PDF compilato, ZIP di output, risposte API
  salvate e uno script di prova la cui logica e' gia' in server.js

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FRwidp8pte45RXaecqJaAe
…ra Vercel

Audit di sicurezza in vista del deploy pubblico. L'XSS era sfruttabile: un
.tex con <script> produceva JavaScript eseguito sull'origine dell'app, cosa
verificata su browser reale prima e dopo la correzione.

Sicurezza
- il testo proveniente dal .tex (titolo, domande, opzioni, celle di tabella)
  finiva grezzo nell'HTML generato: ora passa tutto da un escaping
  sistematico, con i frammenti generati dal server tenuti separati
- gli output erano salvati in backend/static con nome da Math.random(),
  quindi indovinabili ed enumerabili fra utenti diversi; ora viaggiano nella
  risposta di /compile, la cartella di lavoro e' cancellata prima dell'invio
  e la rotta /static non esiste piu'
- l'anteprima del quiz gira in un iframe sandbox senza allow-same-origin,
  cioe' in un'origine opaca che non puo' toccare la pagina ospite
- aggiunte CSP, X-Content-Type-Options, X-Frame-Options, Referrer-Policy,
  Cross-Origin-Opener-Policy e Permissions-Policy
- aggiunti rate limiting per IP su /compile, allowlist delle estensioni e
  tetto complessivo sull'upload
- /api/download/package.zip scriveva sempre sullo stesso percorso: due
  download simultanei potevano corrompersi a vicenda

Formule
- l'HTML generato caricava MathJax da cdn.jsdelivr.net: senza rete le formule
  restavano testo grezzo e ogni apertura rivelava l'IP del lettore a terzi.
  Sostituito con un renderer lato server (frazioni, radici, apici, pedici,
  lettere greche, operatori grandi, ~100 simboli)
- il PDF usa il font Unicode DejaVu, gia' nel repo ma mai collegato come
  @pdf-lib/fontkit: i simboli non vengono piu' degradati in ASCII
- corretto un bug per cui, in assenza di \author o \date, il parser leggeva
  la prima graffa del file e stampava "article" come autore

Deploy e legale
- vercel.json e api/index.js; nessuna scrittura avviene piu' nella cartella
  del progetto, che su Vercel e' di sola lettura: tutto sotto /tmp
- pagine /termini e /privacy, collegate dai footer, scritte per corrispondere
  al comportamento effettivo del codice (contengono segnaposto da compilare)
- la CI ora verifica anche XSS, assenza di persistenza, header di sicurezza,
  rifiuto delle estensioni non ammesse e assenza di richieste esterne

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FRwidp8pte45RXaecqJaAe
@Francy2009
Francy2009 merged commit 556ffa9 into main Aug 9, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants