File size: 3,104 Bytes
eb6572b
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
import { chromium } from 'playwright';
import fs   from 'fs';
import path from 'path';

/**
 * Launch Playwright, sign in to n8n if needed, refresh cookie,
 * save a screenshot, return status object.
 */
export async function runLogin() {
  let browser;
  try {
    browser = await chromium.launch({ args: ['--no-sandbox'] });

    /* ---------- reuse cookie ---------- */
    const hasState = fs.existsSync('/opt/state.json');
    const context  = hasState
      ? await browser.newContext({ storageState: '/opt/state.json' })
      : await browser.newContext();

    await context.tracing.start({ screenshots: true, snapshots: true });

    const page    = await context.newPage();
    const baseUrl = process.env.N8N_URL || 'http://localhost:5678/';
    await page.goto(baseUrl, { waitUntil: 'networkidle', timeout: 60000 });

    /* ---------- BASIC AUTH (optional) ---------- */
    const basicUserInput = page.locator('input[type="text"]');
    if (process.env.BASIC_USER && await basicUserInput.count()) {
      await basicUserInput.fill(process.env.BASIC_USER);
      await page.fill('input[type="password"]', process.env.BASIC_PASS || '');
      await page.press('input[type="password"]', 'Enter');
    }

    /* ---------- detect current page ---------- */
    const signInForm  = page.locator('[data-test-id="signin-form"]');
    const overviewTab = page.getByRole('link', { name: /^overview$/i });

    let needSignIn = false;
    try {
      await Promise.race([
        signInForm.waitFor({ state: 'visible', timeout: 45000 }),
        overviewTab.waitFor({ state: 'visible', timeout: 45000 }),
      ]);
      needSignIn = await signInForm.count() > 0;
    } catch (_) {
      needSignIn = false;  // neither selector appeared
    }

    /* ---------- perform sign-in ---------- */
    if (needSignIn) {
      const email = page.locator(
        'input[name="emailOrLdapLoginId"], input[name="email"]'
      ).first();
      const pass  = page.locator('input[name="password"]').first();

      await email.fill(process.env.N8N_EMAIL || '');
      await pass.fill(process.env.N8N_PASSWORD || '');
      await page.getByRole('button', { name: /sign in/i }).click();
      await overviewTab.waitFor({ state: 'visible', timeout: 60000 });
    }

    /* ---------- save cookie & screenshot ---------- */
    await context.storageState({ path: '/opt/state.json' });
    try {
      const dir = '/opt/log';
      fs.mkdirSync(dir, { recursive: true });
      const ts = new Date().toISOString().replace(/[:T]/g, '-').split('.')[0];
      const file = path.join(dir, `overview-${ts}.png`);
      await page.screenshot({ path: file, fullPage: true });
      console.log('📸 Screenshot saved ->', file);
    } catch (e) {
      console.warn('⚠️  Could not save screenshot:', e.message);
    }

    await context.tracing.stop({ path: '/opt/trace.zip' });
    return { ok: true, loggedIn: needSignIn ? 'fresh' : 'cookie' };
  } catch (err) {
    console.error('❌ runLogin error:', err);
    return { ok: false, error: err.message };
  } finally {
    if (browser) await browser.close();
  }
}