Migrate backend from Flask to Express + add security hardening - #1
Merged
Merged
Conversation
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
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
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
server.jsnow handles all routing, file uploads, and compilation orchestrationos.tmpdir()/texforgeinstead ofbackend/staticandbackend/compiled, making the project directory read-only (required for serverless platforms like Vercel)Security Hardening
escapeHtml()function and complete LaTeX text rendering pipeline (renderLatexText(),mathToHtml()) that safely converts LaTeX to HTML with proper escaping of all user-controlled content/staticroute no longer exists; outputs don't persist on serversandbox="allow-scripts"iframe with opaque origincdn.jsdelivr.net; math rendering now done server-side with Unicode symbolsContent-Security-Policy,X-Content-Type-Options,X-Frame-Options,Referrer-Policy,Cross-Origin-Opener-Policy,Permissions-Policy/compile— 12 requests per minute per IPLaTeX Rendering
GREEK,SYMBOLS,BIG_OPERATORS,MATH_FUNCTIONSmappings for Unicode math rendering\frac,\sqrtnow render as proper HTML structures with CSS classes\text,\mathbf,\mathit, etc. properly handled^and_convert to<sup>and<sub>with Unicode charactersASCII_MATHtable provides ASCII approximations when Unicode symbols can't be embedded in PDFDocumentation & Pages
/docs/documentation site — Comprehensive guide toquizstruct.sty, question types, and compilation flow/privacyand/termini(terms of service) with proper placeholders for contact infoindex.htmlwith improved UI, preview panel with sandbox isolation, template buttonsDeployment
Dockerfilewith Node 22 + TeX Live + tex4ht,docker-compose.ymlfor production stackapi/index.jsandvercel.jsonfor deployment on Vercel (uses/tmpfor temp files)PORTnow configurable viaprocess.env.PORTTesting & CI
ci.ymlworkflow tests Node server startup, frontend serving, API endpoints, and compilation with actual.texfilestest_*.jsonandtest_*.pdffilesImplementation Details
pdf-liband HTML via internal parser even without TeX Live installedfontkitfor custom font handling inhttps://claude.ai/code/session_01FRwidp8pte45RXaecqJaAe