import { mkdtemp, readdir, readFile } from "node:fs/promises" import { tmpdir } from "node:os" import { join } from "node:path" import pino from "pino" import { describe, expect, it, vi } from "vitest" import { loadConfig } from "../src/config/env.js" import { EMAIL_TEMPLATES, type EmailTemplate, type EmailTemplates, type OrderEmailData, renderEmail } from "../src/emails/index.js" import { BrevoTransport, ConsoleTransport, EmailDeliveryError, EmailSender, type EmailTransport, renderMessage, ResendTransport, } from "../src/services/email.js" import { LogCapture, testConfig } from "./helpers.js" const XSS = `&"'` const EVIL_URL = "javascript:alert(1)" const order: OrderEmailData = { number: 12, email: "cliente@example.com", customerName: `Mario ${XSS}`, guest: false, items: [{ name: `Addolcitore ${XSS}`, quantity: 2, total: 238000 }], itemTotal: 238000, shippingTotal: 1500, discountTotal: 0, taxTotal: 43188, total: 239500, shippingAddress: ["Mario Rossi", `Via Roma 1 ${XSS}`, "20100 Milano (MI)"], } /** Dati di esempio per ogni template, con contenuti ostili nei campi testuali. */ const samples: { [K in EmailTemplate]: EmailTemplates[K] } = { "verify-email": { firstName: `Mario ${XSS}`, link: "https://area.example.it/verify-email?token=abc" }, "reset-password": { firstName: `Mario ${XSS}`, link: "https://area.example.it/reset-password?token=abc" }, "register-existing": { firstName: `Mario ${XSS}`, forgotPasswordUrl: "https://area.example.it/forgot-password" }, "order-confirmation": { order, ordersUrl: "https://area.example.it/ordini" }, "order-placed-admin": { order }, "order-canceled": { order }, "order-shipped": { order, tracking: [{ number: `BRT${XSS}`, url: "https://track.example/BRT1" }] }, "quote-request-admin": { name: `Ugo ${XSS}`, email: "ugo@example.com", phone: "333 1234567", province: "TO", summary: [{ label: "Soluzione", value: `Fotovoltaico ${XSS}` }], adminUrl: "https://area.example.it/admin/preventivi/1", }, "quote-request-received": { name: `Ugo ${XSS}`, solutionTitle: `Addolcitore ${XSS}`, summary: [{ label: "Investimento", value: `1.500 € ${XSS}` }], disclaimer: "Stima indicativa", }, "quote-sent": { firstName: `Ugo ${XSS}`, quoteNumber: "2026-0007", title: `Impianto FV 6 kW ${XSS}`, amountCents: 990000, validUntil: "2026-11-30", link: "https://area.example.it/preventivi/7", }, "ticket-reply": { firstName: `Ugo ${XSS}`, ticketSubject: `Perdita ${XSS}`, message: `Riga 1\nRiga 2 ${XSS}`, link: "https://area.example.it/ticket/3", }, "staff-notification": { title: `Nuovo ticket ${XSS}`, intro: `Ticket da ${XSS}`, rows: [{ label: "Oggetto", value: `Perdita ${XSS}` }], url: "https://area.example.it/admin/ticket/1", }, "installer-approved": { firstName: `Paolo ${XSS}`, businessName: `Impianti ${XSS}`, link: "https://area.example.it/installatori" }, "installer-rejected": { firstName: `Paolo ${XSS}`, businessName: `Impianti ${XSS}`, reason: `Motivo ${XSS}` }, "showroom-booking-confirmed": { name: `Ugo ${XSS}`, requestedAt: "2026-10-10T13:00:00.000Z", people: 3, notes: `Parcheggio ${XSS}`, }, } describe("template", () => { it("c'è un esempio per ogni template registrato", () => { expect(Object.keys(samples).sort()).toEqual([...EMAIL_TEMPLATES].sort()) }) for (const template of EMAIL_TEMPLATES) { it(`${template}: oggetto, HTML con layout, testo; dati escapati`, () => { const r = renderEmail(template, samples[template] as never) expect(r.subject.length).toBeGreaterThan(5) expect(r.subject).not.toMatch(/[\r\n]/) expect(r.html).toMatch(/^/) expect(r.html).toContain("ITI TECHNOLOGY") expect(r.text).toContain("ITI TECHNOLOGY") // Nessun contenuto ostile non escapato nell'HTML expect(r.html).not.toContain("