UNPKG

chromancer

Version:

A powerful command-line interface for automating Chrome browser using Playwright. Perfect for web scraping, automation, testing, and browser workflows.

223 lines (222 loc) 8.49 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); const core_1 = require("@oclif/core"); const base_js_1 = require("../base.js"); const fs_1 = require("fs"); class Cookies extends base_js_1.BaseCommand { static description = 'Complete cookie management - save/load sessions, inspect values, set custom cookies, and maintain authenticated states across runs'; static examples = [ '<%= config.bin %> <%= command.id %> list', '<%= config.bin %> <%= command.id %> get sessionId', '<%= config.bin %> <%= command.id %> set name=value', '<%= config.bin %> <%= command.id %> delete sessionId', '<%= config.bin %> <%= command.id %> clear', '<%= config.bin %> <%= command.id %> save --output cookies.json', '<%= config.bin %> <%= command.id %> load --file cookies.json', ]; static args = { action: core_1.Args.string({ description: 'Cookie action', options: ['list', 'get', 'set', 'delete', 'clear', 'save', 'load'], required: true, }), value: core_1.Args.string({ description: 'Cookie name or name=value pair', }), }; static flags = { ...base_js_1.BaseCommand.baseFlags, output: core_1.Flags.string({ char: 'o', description: 'Output file for save action', default: 'cookies.json', }), file: core_1.Flags.string({ char: 'f', description: 'Input file for load action', }), domain: core_1.Flags.string({ description: 'Cookie domain', }), path: core_1.Flags.string({ description: 'Cookie path', default: '/', }), secure: core_1.Flags.boolean({ description: 'Secure cookie flag', default: false, }), httpOnly: core_1.Flags.boolean({ description: 'HttpOnly cookie flag', default: false, }), sameSite: core_1.Flags.string({ description: 'SameSite cookie attribute', options: ['Strict', 'Lax', 'None'], }), expires: core_1.Flags.integer({ description: 'Cookie expiration timestamp', }), }; async run() { const { args, flags } = await this.parse(Cookies); await this.connectToChrome(flags.port, flags.host, flags.launch, flags.profile, flags.headless, flags.verbose, flags.keepOpen); if (!this.page || !this.context) { this.error('Failed to connect to Chrome'); } await this.manageCookies(this.page, args.action, args.value); } async manageCookies(page, action, value) { const { flags } = await this.parse(Cookies); switch (action) { case 'list': await this.listCookies(page); break; case 'get': if (!value) this.error('Cookie name required for get action'); await this.getCookie(page, value); break; case 'set': if (!value) this.error('Cookie data required for set action (name=value)'); await this.setCookie(page, value); break; case 'delete': if (!value) this.error('Cookie name required for delete action'); await this.deleteCookie(page, value); break; case 'clear': await this.clearCookies(page); break; case 'save': await this.saveCookies(page, flags.output); break; case 'load': if (!flags.file) this.error('File path required for load action (use --file)'); await this.loadCookies(page, flags.file); break; default: this.error(`Unknown action: ${action}`); } } async listCookies(page) { const cookies = await this.context.cookies(); if (cookies.length === 0) { this.log('No cookies found'); return; } this.log(`Found ${cookies.length} cookies:\n`); for (const cookie of cookies) { this.log(`🍪 ${cookie.name}`); this.log(` Value: ${cookie.value}`); this.log(` Domain: ${cookie.domain}`); this.log(` Path: ${cookie.path}`); if (cookie.expires && cookie.expires > 0) { this.log(` Expires: ${new Date(cookie.expires * 1000).toISOString()}`); } if (cookie.secure) this.log(' Secure: ✓'); if (cookie.httpOnly) this.log(' HttpOnly: ✓'); if (cookie.sameSite) this.log(` SameSite: ${cookie.sameSite}`); this.log(''); } } async getCookie(page, name) { const { flags } = await this.parse(Cookies); const cookies = await this.context.cookies(); const cookie = cookies.find(c => c.name === name); if (!cookie) { this.error(`Cookie not found: ${name}`); } this.log(`🍪 ${cookie.name} = ${cookie.value}`); if (flags.verbose) { this.logVerbose('Cookie details', { domain: cookie.domain, path: cookie.path, secure: cookie.secure, httpOnly: cookie.httpOnly, sameSite: cookie.sameSite, expires: cookie.expires ? new Date(cookie.expires * 1000).toISOString() : 'Session', }); } } async setCookie(page, value) { const { flags } = await this.parse(Cookies); // Parse name=value format const [name, ...valueParts] = value.split('='); if (!name || valueParts.length === 0) { this.error('Invalid cookie format. Use: name=value'); } const cookieValue = valueParts.join('='); // Handle values with = in them // Get current URL for domain const url = page.url(); const urlObj = new URL(url); const cookie = { name: name.trim(), value: cookieValue.trim(), domain: flags.domain || urlObj.hostname, path: flags.path, secure: flags.secure, httpOnly: flags.httpOnly, sameSite: flags.sameSite, expires: flags.expires || -1, // -1 means session cookie }; await this.context.addCookies([cookie]); this.log(`✅ Cookie set: ${name}`); if (flags.verbose) { this.logVerbose('Cookie set', cookie); } } async deleteCookie(page, name) { const cookies = await this.context.cookies(); const cookie = cookies.find(c => c.name === name); if (!cookie) { this.warn(`Cookie not found: ${name}`); return; } // Delete by setting expiration to past await this.context.addCookies([{ ...cookie, expires: 0, }]); this.log(`✅ Cookie deleted: ${name}`); } async clearCookies(page) { const cookies = await this.context.cookies(); if (cookies.length === 0) { this.log('No cookies to clear'); return; } await this.context.clearCookies(); this.log(`✅ Cleared ${cookies.length} cookies`); } async saveCookies(page, outputPath) { const cookies = await this.context.cookies(); if (cookies.length === 0) { this.warn('No cookies to save'); return; } await fs_1.promises.writeFile(outputPath, JSON.stringify(cookies, null, 2)); this.log(`✅ Saved ${cookies.length} cookies to: ${outputPath}`); } async loadCookies(page, filePath) { try { const content = await fs_1.promises.readFile(filePath, 'utf-8'); const cookies = JSON.parse(content); if (!Array.isArray(cookies)) { this.error('Invalid cookie file format'); } await this.context.addCookies(cookies); this.log(`✅ Loaded ${cookies.length} cookies from: ${filePath}`); } catch (error) { this.error(`Failed to load cookies: ${error.message}`); } } } exports.default = Cookies;