richardtekula d26e537244 fix: Harden security - CORS, XSS, file uploads, error handling
- Restrict no-origin CORS bypass to development only
- Activate xss-clean middleware for input sanitization
- Add MIME type whitelist and filename sanitization to file uploads
- Reduce project upload limit from 50MB to 20MB
- Stop leaking stack traces in error responses

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-26 15:21:44 +01:00
2025-12-02 09:48:42 +01:00
2025-12-02 09:48:42 +01:00
2025-12-29 09:02:24 +01:00
2025-12-04 10:27:34 +01:00

CRM Server Architektúra a flow

Tento dokument popisuje, ako backend funguje: aká je štruktúra kódu, akou cestou prechádza požiadavka, aké služby spolu komunikujú a kde sa riešia bezpečnostné a chybové scenáre. Všetky cesty v kóde sú písané v ES modules.

Základný stack

  • Express 4 (ESM) + Drizzle ORM (PostgreSQL)
  • JWT pre prístupové/refresh tokeny (httpOnly cookies), bcrypt pre heslá
  • Zod na validačné schémy, helmet, cors, express-rate-limit
  • JMAP integrácia pre e-maily (Truemail) + AES-256-GCM šifrovanie hesiel k e-mail účtom

Štruktúra priečinkov (hlavné časti)

  • src/app.js skladá middleware pipeline a mountuje routes, pridáva notFound/error handler.
  • src/index.js spúšťací bod servera.
  • src/routes/ deklarácie endpointov (1 súbor = 1 doména). Všetky používajú middlewares + volajú controller.
  • src/controllers/ spracovanie requestu, volanie service vrstvy, odoslanie odpovedí. Chyby posielajú cez next(err).
  • src/services/ biznis logika a práca s DB/JMAP (bez Express závislosti).
  • src/middlewares/ auth (JWT + role), security (rate limiting, Zod validateInput), global (validateBody pattern check, 404, error handler).
  • src/utils/ errors.js (AppError a formátovanie), jwt.js, password.js, logger.js.
  • src/validators/ Zod schémy pre vstupy.
  • src/db/ Drizzle schéma a config.

Životný cyklus požiadavky (pipeline)

  1. Logovanie: morgan('dev') (len stdout).
  2. Bezpečnostné hlavičky: helmet s CSP (self + inline styles) a HSTS (preload, subdomains).
  3. CORS: povolený pôvod z CORS_ORIGIN (default http://localhost:5173), credentials povolené.
  4. Body parsers: express.json a express.urlencoded (limit 10MB), cookieParser pre JWT v cookies.
  5. Global validateBody: rýchly regex-detektor podozrivých payloadov (loguje a vráti 400 pri matches).
  6. Rate limiting: apiRateLimiter na /api/* (100 req/15 min v production, 1000 v dev). Špecifické limitery na login a citlivé operácie sa aplikujú v routes.
  7. Routes: auth, admin, contacts, emails (CRM), email-accounts, timesheets, companies, projects, todos, time-tracking, notes.
  8. 404: notFound middleware nastaví 404 a pošle ďalej ako Error.
  9. Global error handler: errorHandler loguje, zvolí status (err.statusCode > res.statusCode ≥400 > 500) a formátuje pomocou formatErrorResponse. Ak už sú hlavičky poslané, púšťa chybu ďalej.

Validácia a bezpečnosť

  • Zod validácia: validateBody/validateQuery/validateParams (v middlewares/security/validateInput.js) na úrovni routes; nahrádzajú req.body/query/params validovanými dátami.
  • Auth: authenticate vytiahne JWT z Bearer header alebo cookie, overí cez verifyAccessToken, načíta usera (auth.service.getUserById) a uloží do req.user + req.userId.
  • Role: requireRole / requireAdmin / requireOwnerOrAdmin (role middleware) na autorizáciu.
  • Rate limiting: loginRateLimiter (default 5 pokusov/15 min, počíta len neúspechy), sensitiveOperationLimiter (10 prod / 50 dev za 15 min).
  • Šifrovanie: password.encryptPassword používa AES-256-GCM (kľúč zo JWT_SECRET + ENCRYPTION_SALT). Heslá v DB sú bcrypt hashované.
  • Audit logy: audit.service loguje login pokusy, zmeny hesla, role, tvorbu userov atď. do DB + konzoly.

Error handling (kde a ako)

  • Typy chýb: AppError + podtriedy (ValidationError, AuthenticationError, ForbiddenError, NotFoundError, ConflictError, RateLimitError).
  • Formát odpovede: formatErrorResponse vracia { success:false, error:{ message, statusCode, details?, stack? } }. Stack iba v NODE_ENV=development.
  • Použitie: Kontroléry nemajú lokálne try/catch formatovanie; pri chybe volajú next(err). Auth middleware vracia 401 pri Auth chybách, inak púšťa ďalej do globálneho handlera.

Doménové moduly kto koho volá

Autentifikácia (routes/auth.routes.js, auth.controller.js, auth.service.js)

  • /login: loginRateLimitervalidateBody(loginSchema) → controller zavolá authService.loginWithTempPassword (porovná temp/permanent heslo, nastaví lastLogin, vygeneruje tokeny) → audit logLoginAttempt (success/fail) → nastaví httpOnly cookies + response.
  • /set-password: authenticatesensitiveOperationLimitervalidateBody(setPasswordSchema)authService.setNewPassword (bcrypt, zmaže tempPassword) → audit logPasswordChange.
  • /logout, /session: vyžadujú authenticate; logout vyčistí cookies, session vráti req.user.
  • Tokeny: generované v utils/jwt.js (access + refresh); overenie hádže AuthenticationError pri expirácii/neplatnosti.

Admin (routes/admin.routes.js, admin.controller.js)

  • router.use(authenticate) + router.use(requireAdmin) pre všetky admin-only akcie.
  • CRUD nad používateľmi: create (generuje temp heslo + voliteľné linknutie email účtu), get/list, change role, delete. Používa email-account.service pri zakladaní účtu, loguje audit udalosti.

Email účty (routes/email-account.routes.js, email-account.controller.js, email-account.service.js)

  • Každá akcia vyžaduje authenticate.
  • Create: sensitiveOperationLimiter + Zod schéma → service overí JMAP credentials (validateJmapCredentials z email.service.js), šifruje heslo (AES-256-GCM), vytvorí účet a many-to-many link do userEmailAccounts. Ak účet existuje, vie ho len „nasdieliť“ po overení hesla.
  • Set primary: pre konkrétneho používateľa; transakčne zruší ostatné isPrimary a aktivuje účet.
  • Delete: odstráni link, a ak nikto iný účet nepoužíva, zmaže aj samotný účet.
  • Get: vracia účty používateľa; špeciálna funkcia getEmailAccountWithCredentials dešifruje heslo na JMAP operácie.

CRM Emaily (routes/crm-email.routes.js, crm-email.controller.js, crm-email.service.js, jmap.service.js)

  • Všetky endpointy za authenticate.
  • Listing/search: DB filter + fulltext (subject/body/from), alebo JMAP full-text (/search-jmap). Filtrovanie podľa účtu, kontaktu, stavu prečítania.
  • Threads: /thread/:threadId načíta konverzáciu; /thread/:threadId/read označí všetky maily v threade.
  • Sync: /sync spustí fetch z JMAP pre daného používateľa/účet.
  • Mark contact read: /contact/:contactId/read označí všetky maily od kontaktu ako prečítané.
  • Reply: /reply cez JMAP; používa dešifrované heslo z email-account service.
  • Unread count: /unread-count agreguje per účet.

Kontakty (routes/contact.routes.js, contact.controller.js, contact.service.js)

  • Všetko za authenticate.
  • Get/Discover: zoznam kontaktov (voliteľný filter accountId), discover číta unikátnych odosielateľov z JMAP.
  • Create: validácia + uloženie, následne auto-sync všetkých emailov od tohto odosielateľa.
  • Update/Delete: meno/poznámky, prípadne zmazanie; pri delete ostávajú emaily, len sa odpojí contact_id.
  • Link/Unlink company a create company from contact využívajú company service.

Companies (routes/company.routes.js, company.controller.js, company.service.js, company-email.service.js, company-reminder.service.js)

  • authenticate povinné.
  • CRUD firmy, plus email threads pre firmu (agregácia emailov naprieč účtami používateľa).
  • Unread counts per firma (agreguje emaily podľa kontaktov a účtov).
  • Notes (vnořené /:companyId/notes) používajú note.service.
  • Reminders: CRUD + summary/endpoints na prehľad (upcoming, counts, summary). Všetko cez company-reminder.service.

Projekty (routes/project.routes.js, project.controller.js, project.service.js)

  • authenticate povinné.
  • CRUD projektov, správa členov projektu (assign/update role/remove), projektové poznámky (vrátane reminderAt).

Todos (routes/todo.routes.js, todo.controller.js, todo.service.js)

  • authenticate; CRUD + toggle completed.

Poznámky (routes/note.routes.js, note.controller.js, note.service.js)

  • authenticate; všeobecné poznámky s filtrom na company/project/todo/contact; CRUD operácie.

Time Tracking (routes/time-tracking.routes.js, time-tracking.controller.js, time-tracking.service.js)

  • authenticate; Zod validácia na start/stop/update.
  • Start/Stop: vytvára/uzatvára bežiaci záznam (oprávnenie viazané na req.userId).
  • Bežiace položky: /running (aktuálne pre usera), /running-all (všetkých userov dashboard).
  • Listing/Filters: všeobecný listing, mesačné výpisy a štatistiky, detail/relations.
  • Generate timesheet: vytvorí XLSX výstup za mesiac (využíva exceljs).

Timesheets upload (routes/timesheet.routes.js, timesheet.controller.js, timesheet.service.js)

  • authenticate; Multer s memory storage a limit 5MB, whitelist MIME (PDF, XLSX, XLS). Admin môže nahrávať za iných, inak len za seba. Ukladá súbory do uploads/timesheets.

Admin (už popísané vyššie)

Audit (audit.service.js)

  • Jednotné logovanie udalostí do DB + konzoly (tag [AUDIT]). Použité v auth flow a user managemente; možno rozšíriť na ďalšie služby.

Pomocné utility

  • utils/errors.js definícia AppError podtried + formatErrorResponse.
  • utils/jwt.js generovanie/verifikácia access/refresh tokenov.
  • utils/password.js bcrypt hash/compare, generovanie temp hesla, AES-256-GCM encrypt/decrypt pre email heslá.
  • utils/logger.js farebný stdout logger (info/success/warn/error/debug/audit).

Request → DB/JMAP tok (v skratke)

RouteZod middleware (+ auth/role/rate-limit) → ControllerServiceDB (Drizzle) alebo JMAP → späť do controller → JSON response. Chyby: buď AppError (očakávané, neseká stack v prod), alebo neočakávané → global errorHandler.

Dôležité závislosti medzi modulmi

  • authMiddleware závisí na utils/jwt a auth.service (pre user fetch). Bez prístupu k DB nie je možné overiť token.
  • crm-email.service používa jmap.service + email-account.service (pre dešifrované heslo) + DB schémy.
  • contact.service pri vytvorení kontaktu volá crm-email.service na sync emailov od odosielateľa.
  • company.controller používa company-email.service (agregácia email threadov) a note.service / company-reminder.service.
  • time-tracking.service používa Drizzle schémy timeEntries, projects, todos, companies, users na joiny a agregácie.
  • timesheet.controller/routes využívajú Multer; uloženie súboru/metadata robí timesheet.service.

Ako rozširovať

  • Nový endpoint: pridaj Zod schému do validators, zapoj validateBody/Params/Query, použi authenticate/requireAdmin podľa potreby, v controllery volaj service a pri chybe next(err).
  • Nová logika: implementuj v services (bez Express závislosti), AppError pri očakávaných stavoch.
  • Error/response shape je centrálne daný errorHandler + formatErrorResponse nechaj ho pracovať.

Environment a spustenie (stručne)

  • Env vars: PORT, CORS_ORIGIN, JWT_SECRET, JWT_REFRESH_SECRET, ENCRYPTION_SALT, RATE_LIMIT_*, DB credentials atď. (pozri .env.example ak existuje / README bezpečnostný checklist).
  • Skripty: npm run dev (nodemon), npm start, npm test (Jest), drizzle migrácie db:generate/push/studio.

Tento README má slúžiť ako rýchla mapa: čo kde je, čo koho volá a kde hľadať validačné/bezpečnostné háky alebo biznis logiku.

Description
No description provided
Readme 5.5 MiB
Languages
JavaScript 92%
HTML 7.9%
Dockerfile 0.1%