lwvwv/save-session.js

117 lines
3.8 KiB
JavaScript
Executable File

#!/usr/bin/env node
const { chromium } = require('playwright');
const fs = require('fs');
const path = require('path');
const readline = require('readline');
const DOWNLOAD_DIR = path.dirname(__filename);
const SESSION_FILE = path.join(DOWNLOAD_DIR, '.session.json');
const ENV_FILE = path.join(DOWNLOAD_DIR, 'env');
// Read configuration from env file
function loadConfig() {
const content = fs.readFileSync(ENV_FILE, 'utf8');
const config = {};
// Match $VAR = "value" patterns
const matches = content.matchAll(/\$(\w+)\s*=\s*"([^"]*)"/g);
for (const match of matches) {
config[match[1]] = match[2];
}
return config;
}
const config = loadConfig();
const PORTAL_URL = config.PORTAL_URL || 'https://portal.lwv.org';
const MEMBERSHIP_URL = config.MEMBERSHIP_URL || 'https://portal.lwv.org/groups/43a93df1-901a-4676-88c3-f4ea430d4884/league_membership_state_view';
function waitForEnter() {
const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
return new Promise(resolve => rl.question('', () => {
rl.close();
resolve();
}));
}
async function saveSession() {
console.log('Starting browser for session save...');
console.log('');
console.log('INSTRUCTIONS:');
console.log('1. A browser window will open');
console.log('2. Log in using the magic link method (email)');
console.log('3. After logging in and seeing the home page, come back here');
console.log('4. Press Enter to save the session');
console.log('');
console.log(`Portal URL: ${PORTAL_URL}`);
console.log(`Membership URL: ${MEMBERSHIP_URL}`);
console.log('');
const browser = await chromium.launch({
headless: false,
devtools: true
});
const context = await browser.newContext();
const page = await context.newPage();
try {
// Go to portal
await page.goto(PORTAL_URL, { waitUntil: 'networkidle', timeout: 60000 });
console.log('Browser opened. Please log in using magic link...');
console.log('Press Enter after you have logged in and can see the home page.');
// Wait for user to press Enter
await waitForEnter();
// Navigate to membership page to verify access
console.log('Navigating to membership page...');
await page.goto(MEMBERSHIP_URL, { waitUntil: 'networkidle', timeout: 60000 });
await page.waitForTimeout(2000);
console.log('Membership page loaded. Saving session...');
// Get cookies and storage state
const cookies = await context.cookies();
const storageState = await context.storageState();
// Save session data - indefinite expiry (set to 10 years)
const sessionData = {
cookies: cookies,
storageState: storageState,
savedAt: new Date().toISOString(),
expiresAt: new Date(Date.now() + 3650 * 24 * 60 * 60 * 1000).toISOString() // 10 years
};
fs.writeFileSync(SESSION_FILE, JSON.stringify(sessionData, null, 2));
console.log(`Session saved to ${SESSION_FILE}`);
console.log(`Saved ${cookies.length} cookies`);
// Verify session works by checking membership page
console.log('Verifying session...');
const testPage = await context.newPage();
await testPage.goto(MEMBERSHIP_URL, { waitUntil: 'networkidle', timeout: 30000 });
const testContent = await testPage.content();
if (testContent.includes('Local League Membership') || testContent.includes('submit-export')) {
console.log('Session verified successfully!');
} else {
console.log('Warning: Session may not have full access');
}
await testPage.close();
console.log('\nSession save complete! You can now run download-roster.js');
} catch (error) {
console.error('Error:', error.message);
throw error;
} finally {
await browser.close();
}
}
saveSession().catch(err => {
console.error('Failed:', err);
process.exit(1);
});