/** * PMG quarantine capture — the customer self-service spam quarantine portal. * * Captures: * - email-quarantine-login.png Login screen showing the "Request Quarantine * Link" button next to Login. * - email-quarantine-request.png The "Request Quarantine Link" dialog with an * email address entered. * - email-quarantine-list.png The authenticated quarantine grid showing held * mail, redacted to generic example content. * - email-quarantine-actions.png A selected message with the Whitelist / * Blacklist / Deliver / Delete toolbar visible. * * Viewport-only (1440x900, deviceScaleFactor 2), redacted: the real server * hostname, the real test mailbox address, and the real (internal-test-looking) * sender/subject/body text are all swapped for generic customer-facing examples. * * Read-only: never actually delivers/whitelists/blacklists/deletes anything. */ import { chromium, type Page } from 'playwright'; import { mkdir } from 'node:fs/promises'; import { resolve, dirname } from 'node:path'; import { fileURLToPath } from 'node:url'; const __dirname = dirname(fileURLToPath(import.meta.url)); const OUT_DIR = resolve(__dirname, '../../src/assets/screenshots/email'); const BASE = process.env.PMG_BASE || 'https://pmg01.cloud-hosting.io:8006'; const TICKET_URL = process.env.PMG_TICKET_URL; // full quarantine?ticket=... URL /** Swap real fleet/test identifiers for believable generic customer-facing text. */ async function redact(page: Page) { await page.evaluate(() => { const swaps: [RegExp, string][] = [ [/pmg01\.cloud-hosting\.io/gi, 'mail.yourdomain.com'], [/claude@darksideofperfection\.com/gi, 'you@yourdomain.com'], [/pmg-pilot-tester@anthropic\.com/gi, 'prizes@totally-legit-sweepstakes.example'], [/SPAM: PMG pilot - spam detection test \(GTUBE\) \(retry\)/g, "SPAM: You've WON a prize!!!"], [/SPAM: PMG pilot - clean delivery test \(retry\)/g, 'SPAM: Limited time offer - act now'], [/This is a clean end-to-end delivery test, retried after greylist window\./g, 'Congratulations! You have been selected to receive an exclusive reward. Click below to claim yours before this offer expires.'], [/GTUBE retry test\./g, "You've been selected for an exclusive reward!"], [/XJS\*C4JDBQADN1\.NSBN3\*2IDNEN\*GTUBE-STANDARD-ANTI-UBE-TEST-EMAIL\*C\.34X/g, 'Click here to claim your prize before this limited-time offer expires: http://totally-legit-sweepstakes.example/claim'], [/\b1010\b/g, '8.4'], ]; const docs: Document[] = [document]; for (const f of Array.from(document.querySelectorAll('iframe'))) { try { const doc = (f as HTMLIFrameElement).contentDocument; if (doc) docs.push(doc); } catch { /* cross-origin, skip */ } } for (const root of docs) { const walker = root.createTreeWalker(root.body, NodeFilter.SHOW_TEXT); const nodes: Text[] = []; let n: Node | null = walker.nextNode(); while (n) { nodes.push(n as Text); n = walker.nextNode(); } for (const node of nodes) { let v = node.nodeValue ?? ''; for (const [re, rep] of swaps) v = v.replace(re, rep); if (v !== node.nodeValue) node.nodeValue = v; } } }); } async function main() { if (!TICKET_URL) throw new Error('missing env: PMG_TICKET_URL'); await mkdir(OUT_DIR, { recursive: true }); const browser = await chromium.launch({ headless: true }); const ctx = await browser.newContext({ ignoreHTTPSErrors: true, viewport: { width: 1440, height: 900 }, deviceScaleFactor: 2, }); const page = await ctx.newPage(); try { // --- Shot 1: login screen, showing the Request Quarantine Link button --- await page.goto(`${BASE}/quarantine`, { waitUntil: 'networkidle' }); await page.waitForSelector('text=Request Quarantine Link', { state: 'visible' }); await page.waitForTimeout(300); await redact(page); let p = resolve(OUT_DIR, 'email-quarantine-login.png'); await page.locator('.x-window').first().screenshot({ path: p }); console.log(`captured email-quarantine-login -> ${p}`); // --- Shot 2: the Request Quarantine Link dialog, filled in --- await page.getByRole('button', { name: 'Request Quarantine Link' }).click(); await page.getByRole('textbox', { name: 'Your E-Mail:' }).fill('you@yourdomain.com'); await page.waitForTimeout(200); p = resolve(OUT_DIR, 'email-quarantine-request.png'); await page.locator('.x-window').last().screenshot({ path: p }); console.log(`captured email-quarantine-request -> ${p}`); // --- Shot 3 & 4: authenticated quarantine view, via the real ticket link --- await page.goto(TICKET_URL, { waitUntil: 'networkidle' }); await page.waitForSelector('grid[aria-label="Spam Quarantine"], .x-grid', { state: 'visible' }).catch(() => {}); await page.waitForTimeout(500); await redact(page); p = resolve(OUT_DIR, 'email-quarantine-list.png'); await page.screenshot({ path: p }); console.log(`captured email-quarantine-list -> ${p}`); // Select the first row to reveal the action toolbar + message preview. const firstRow = page.locator('.x-grid-row').first(); await firstRow.click(); await page.waitForTimeout(500); await redact(page); p = resolve(OUT_DIR, 'email-quarantine-actions.png'); await page.screenshot({ path: p }); console.log(`captured email-quarantine-actions -> ${p}`); } finally { await browser.close(); } } main().catch((err) => { console.error(err); process.exit(1); });