const { chromium } = require('playwright'); const fs = require('fs'); const path = require('path'); const dotenv = require('dotenv'); const speakeasy = require('speakeasy'); // Lade .env-Variablen dotenv.config(); const { USERNAME, PASSWORD, TESTNAME, TOTP_SECRET, LOGIN_URL = 'about:privatebrowsing', LOGOUT_URL = 'about:privatebrowsing', SUCCESS_TEXT = "" } = process.env; const nodemailer = require('nodemailer'); async function sendFailureMail(subject, text, attachments) { const transporter = nodemailer.createTransport({ host: process.env.SMTP_HOST, port: parseInt(process.env.SMTP_PORT, 10), secure: false, // kein TLS tls: { rejectUnauthorized: false } }); await transporter.sendMail({ from: process.env.MAIL_FROM, to: process.env.MAIL_TO, subject, text, attachments }); } if (!USERNAME || !PASSWORD || !TOTP_SECRET) { console.error('❌ Bitte .env mit USERNAME, PASSWORD und TOTP_SECRET konfigurieren'); process.exit(2); } (async () => { const resultDir = '/app/test-results'; const timestamp = new Date().toISOString().replace(/[:.]/g, '-'); const browser = await chromium.launch({ headless: true }); const context = await browser.newContext({}); const page = await context.newPage(); console.log('${TESTNAME}: 1 Login aufrufen'); try { await page.goto(LOGIN_URL); await page.setViewportSize({ width: 1920, height: 937 }); // Click on "Login with UVEK-Portal (e..." await Promise.all([ page.click('span:nth-child(2)'), page.waitForNavigation() ]); await page.screenshot({ path: `/app/test-results/eiamselect-${timestamp}.png`, fullPage: true }); await Promise.all([ page.click('#social-eIAM'), page.waitForNavigation() ]); console.log('✅ Login eiam user eintragen'); await page.click('#isiwebuserid'); await page.fill('#isiwebuserid', USERNAME); await page.screenshot({ path: `/app/test-results/userid-${timestamp}.png`, fullPage: true }); await Promise.all([ // page.click('text=Continue'), page.press('#isiwebuserid', 'Enter'), page.waitForNavigation() ]); console.log('✅ Login eiam pw eintragen'); await page.click('#isiwebpasswd'); await page.fill('#isiwebpasswd', PASSWORD); await page.screenshot({ path: `/app/test-results/pw-${timestamp}.png`, fullPage: true }); await Promise.all([ // page.click('text=Login'), page.press('#isiwebpasswd', 'Enter'), page.waitForNavigation() ]); console.log('✅ Login eiam TOTP generieren'); const totp = speakeasy.totp({ secret: TOTP_SECRET, encoding: 'base32' }); console.log('✅ Login eiam TOTP ${totp}'); console.log('✅ Login eiam TOTP eintragen'); await page.fill('#code2FA', totp); await page.screenshot({ path: `/app/test-results/totp-${timestamp}.png`, fullPage: true }); await Promise.all([ // page.click('text=Continue'), page.press('#code2FA', 'Enter'), page.waitForNavigation() ]); console.log('✅ WhoAmI Webseite warten'); await page.waitForSelector(`text=${SUCCESS_TEXT}`, { timeout: 10000 }); await page.screenshot({ path: `/app/test-results/result-${timestamp}.png`, fullPage: true }); console.log(`🔎 Suche nach Benutzername: ${SUCCESS_TEXT}`); const pageText = await page.textContent('body'); fs.writeFileSync(path.join(resultDir, `final-${timestamp}.html`), await page.content()); fs.writeFileSync(path.join(resultDir, `final-${timestamp}.txt`), pageText); if (pageText.includes(SUCCESS_TEXT)) { console.log('✅ Login erfolgreich – Benutzername sichtbar'); } else { console.error('❌ Benutzername nicht gefunden – Login möglicherweise fehlerhaft'); await page.screenshot({ path: path.join(resultDir, `username-missing_${timestamp}.png`) }); fs.writeFileSync(path.join(resultDir, `page-username-missing_${timestamp}.html`), await page.content()); process.exit(1); } console.log('✅ Login erfolgreich - username sichtbar'); console.log('✅ Logout'); await page.goto(LOGOUT_URL); await Promise.all([ page.click('#kc-logout'), page.waitForNavigation() ]); console.log('✅ Logout erfolgreich'); await page.screenshot({ path: `/app/test-results/logout-${timestamp}.png`, fullPage: true }); await browser.close(); } catch (err) { console.error('❌ Fehler beim Login:', err.message); const screenshotPath = path.join(resultDir, `error_${timestamp}.png`); const htmlPath = path.join(resultDir, `page_${timestamp}.html`); const textPath = path.join(resultDir, `page-${timestamp}.txt`); await page.screenshot({ path: screenshotPath }); const pageText = await page.textContent('body'); fs.writeFileSync(htmlPath, await page.content()); fs.writeFileSync(textPath, pageText); const captchaDetected = await page.evaluate(() => { return document.body.innerText.toLowerCase().includes('captcha') || document.querySelector('input[name="captcha"]') !== null || document.querySelector('.g-recaptcha') !== null; }); await sendFailureMail( '❌ OIDC Login Monitoring fehlgeschlagen', `Fehler beim Login:\n\n${err.message}\n\nZeitpunkt: ${timestamp}`, [ { filename: 'error.png', path: screenshotPath }, { filename: 'page.html', path: htmlPath }, { filename: 'page.txt', path: textPath } ] ); if (captchaDetected) { console.error('🚫 Captcha erkannt – Test wird abgebrochen'); const captchaPath = path.join(resultDir, `captcha_${timestamp}.png`); const htmlPath = path.join(resultDir, `captcha_${timestamp}.html`); const textPath = path.join(resultDir, `captcha_${timestamp}.txt`); await page.screenshot({ path: captchaPath }); fs.writeFileSync(htmlPath, await page.content()); fs.writeFileSync(textPath, await page.evaluate(() => document.body.innerText)); process.exit(3); // spezieller Exit-Code für Captcha } process.exit(1); } finally { await browser.close(); } })();