@puffle/cookiejar 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 DevelopIQ
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,129 @@
1
+ # cookiejar
2
+
3
+ **Local-only cookie bundles for coding agents.**
4
+
5
+ You are already logged into GitHub, Linear, Notion, your admin panels. Your agent is not, and half of
6
+ those things have no MCP server. cookiejar lets you pick the exact cookies you are willing to share,
7
+ group them into a **bundle**, and hand that bundle to an agent with a revocable token — without the
8
+ agent (or anyone else) getting a copy of your whole browser.
9
+
10
+ ```
11
+ browsers cookiejar agents
12
+ ┌──────────────┐ ┌──────────────────┐ ┌────────────────────┐
13
+ │ Chrome │ │ ~/.cookiejar │ │ Devin / Claude │
14
+ │ Safari │─────▶│ bundles, tokens │◀──MCP──│ Codex / curl │
15
+ │ Firefox … │ live │ (encrypted) │ HTTP │ │
16
+ └──────────────┘ read └──────────────────┘ └────────────────────┘
17
+ everything stays on 127.0.0.1
18
+ ```
19
+
20
+ - **Local only.** No account, no cloud, no telemetry. The server binds to `127.0.0.1` and the only
21
+ outbound requests it ever makes are the ones an agent explicitly proxies.
22
+ - **Password protected.** Bundle definitions live in `~/.cookiejar/vault.json`, encrypted with
23
+ scrypt + AES-256-GCM. Agent tokens only work while the jar is unlocked.
24
+ - **Values are never stored.** A bundle records *which* cookies to use. The values are read live from
25
+ the browser on every access, so re-logging in the browser is all it takes to refresh an agent, and a
26
+ stolen vault file leaks nothing but bundle names.
27
+ - **Per-bundle tokens.** Expiry, revocation, an access counter, and an append-only audit log. A token
28
+ can be marked *proxy only*, so the agent can make authenticated requests but never sees a cookie.
29
+
30
+ ## Install
31
+
32
+ Requires Node 22.5+ (for the built-in SQLite reader).
33
+
34
+ ```bash
35
+ npm install -g @puffle/cookiejar
36
+ cookiejar ui --open
37
+ ```
38
+
39
+ Or from source:
40
+
41
+ ```bash
42
+ git clone https://github.com/DevelopIQ-ai/cookiejar
43
+ cd cookiejar
44
+ npm install && npm run build
45
+ node dist/cli.js ui --open
46
+ ```
47
+
48
+ Open http://127.0.0.1:4088, choose a master password, and pick your cookies.
49
+
50
+ ## Using a bundle from an agent
51
+
52
+ Issue a token in **Bundles → Agent access**, then give the agent one of these.
53
+
54
+ **MCP (Devin, Claude Code, Cursor, Codex …)**
55
+
56
+ ```json
57
+ {
58
+ "mcpServers": {
59
+ "cookiejar-ticket-triage": {
60
+ "command": "npx",
61
+ "args": ["-y", "@puffle/cookiejar", "mcp"],
62
+ "env": { "COOKIEJAR_TOKEN": "cjr_…" }
63
+ }
64
+ }
65
+ }
66
+ ```
67
+
68
+ Tools: `describe_bundle`, `get_cookie_header`, `export_cookies`, `http_request`.
69
+
70
+ **CLI**
71
+
72
+ ```bash
73
+ export COOKIEJAR_TOKEN=cjr_…
74
+ cookiejar export --format netscape --out cookies.txt # curl -b cookies.txt …
75
+ cookiejar export --format storage-state # Playwright / Puppeteer
76
+ cookiejar header --url-target https://linear.app/team # a single Cookie header
77
+ ```
78
+
79
+ **HTTP** (the daemon, `Authorization: Bearer cjr_…`)
80
+
81
+ | Endpoint | Purpose |
82
+ | --- | --- |
83
+ | `GET /agent/bundle` | Name, hosts, permissions — no secrets |
84
+ | `GET /agent/cookies?format=netscape\|storage-state\|json` | The jar |
85
+ | `GET /agent/cookies?format=header&url=…` | One `Cookie` header |
86
+ | `POST /agent/fetch` | Proxy a request with the bundle's cookies attached |
87
+
88
+ `POST /agent/fetch` is the safest option: cookies never leave the machine, and the request is refused
89
+ unless the target host is one the bundle actually holds cookies for.
90
+
91
+ ## Browser support
92
+
93
+ | Browser | macOS | Linux | Notes |
94
+ | --- | --- | --- | --- |
95
+ | Chrome, Chromium, Brave, Edge, Arc | ✅ | ✅ | Key from the login Keychain / keyring |
96
+ | Firefox | ✅ | ✅ | Plaintext store |
97
+ | Safari | ✅ | — | Needs **Full Disk Access** for your terminal |
98
+ | Windows Chromium | — | — | App-bound (`v20`) cookies are not supported yet |
99
+
100
+ `cookiejar doctor` prints what can and cannot be read on this machine, and why.
101
+
102
+ Browsers hold a lock on their cookie stores, so cookiejar reads from a temporary copy (including the
103
+ WAL) and never writes to them.
104
+
105
+ ## Security model
106
+
107
+ - The vault protects bundle *definitions*, not cookie values — values live in your browser only.
108
+ - An agent token is worth exactly one bundle, only while the app is unlocked, and only until you hit
109
+ **Revoke** (or the jar auto-locks after 30 idle minutes).
110
+ - Every access is appended to `~/.cookiejar/audit.log` with the bundle, token label, and what was
111
+ asked for. Values are never logged.
112
+ - Prefer *proxy only* tokens and per-site bundles. Cookies are bearer credentials: anything you put in
113
+ a bundle, the agent can act as you with.
114
+ - `Set-Cookie` responses from proxied requests are dropped, so an agent cannot rewrite your session.
115
+
116
+ ## Development
117
+
118
+ ```bash
119
+ npm run dev # daemon with tsx
120
+ npm --prefix ui run dev # Vite UI on :4089, proxying the daemon
121
+ npm test # node:test, includes an end-to-end daemon test
122
+ npm run lint && npm run typecheck
123
+ node scripts/seed-demo-profile.mjs /tmp/cookiejar-demo # fake browser data for UI work
124
+ ```
125
+
126
+ Layout: `src/core` (crypto, vault, browser readers, bundle resolution), `src/server` (local HTTP API),
127
+ `src/mcp` (stdio MCP server), `ui` (React app), `test`.
128
+
129
+ MIT licensed. Issues and PRs welcome.
package/dist/cli.js ADDED
@@ -0,0 +1,151 @@
1
+ #!/usr/bin/env node
2
+ import { execFile } from 'node:child_process';
3
+ import fs from 'node:fs';
4
+ import path from 'node:path';
5
+ import { fileURLToPath } from 'node:url';
6
+ import { startServer } from './server/index.js';
7
+ import { runMcpServer } from './mcp/server.js';
8
+ import { readAllProfiles } from './core/browsers/index.js';
9
+ import { bareDomain } from './core/bundles.js';
10
+ // node:sqlite is how we read cookie stores; its experimental banner is noise here.
11
+ process.removeAllListeners('warning');
12
+ process.on('warning', (warning) => {
13
+ if (warning.name !== 'ExperimentalWarning')
14
+ console.warn(`${warning.name}: ${warning.message}`);
15
+ });
16
+ const DEFAULT_PORT = Number(process.env.COOKIEJAR_PORT ?? 4088);
17
+ const DEFAULT_URL = process.env.COOKIEJAR_URL ?? `http://127.0.0.1:${DEFAULT_PORT}`;
18
+ function parseArgs(argv) {
19
+ const flags = new Map();
20
+ const [command = 'ui', ...rest] = argv;
21
+ for (let i = 0; i < rest.length; i++) {
22
+ const arg = rest[i];
23
+ if (!arg.startsWith('--'))
24
+ continue;
25
+ const [name, inline] = arg.slice(2).split('=', 2);
26
+ if (inline !== undefined)
27
+ flags.set(name, inline);
28
+ else if (rest[i + 1] && !rest[i + 1].startsWith('--'))
29
+ flags.set(name, rest[++i]);
30
+ else
31
+ flags.set(name, true);
32
+ }
33
+ return { command, flags };
34
+ }
35
+ const flagString = (args, name, fallback) => {
36
+ const value = args.flags.get(name);
37
+ return typeof value === 'string' ? value : fallback;
38
+ };
39
+ function openBrowser(url) {
40
+ const opener = process.platform === 'darwin' ? 'open' : process.platform === 'win32' ? 'explorer' : 'xdg-open';
41
+ execFile(opener, [url], () => {
42
+ // Opening a browser is a convenience; the URL is printed regardless.
43
+ });
44
+ }
45
+ function uiDir() {
46
+ const here = path.dirname(fileURLToPath(import.meta.url));
47
+ for (const candidate of [path.join(here, 'ui'), path.join(here, '..', 'ui', 'dist'), path.join(here, '..', 'dist', 'ui')]) {
48
+ if (fs.existsSync(path.join(candidate, 'index.html')))
49
+ return candidate;
50
+ }
51
+ return path.join(here, 'ui');
52
+ }
53
+ function requireToken(args) {
54
+ const token = flagString(args, 'token') ?? process.env.COOKIEJAR_TOKEN;
55
+ if (!token) {
56
+ console.error('A bundle token is required. Pass --token or set COOKIEJAR_TOKEN.');
57
+ process.exit(2);
58
+ }
59
+ return token;
60
+ }
61
+ async function agentGet(args, path) {
62
+ const base = flagString(args, 'url', DEFAULT_URL);
63
+ const response = await fetch(new URL(path, base), { headers: { authorization: `Bearer ${requireToken(args)}` } });
64
+ const text = await response.text();
65
+ if (!response.ok) {
66
+ console.error(text);
67
+ process.exit(1);
68
+ }
69
+ return text;
70
+ }
71
+ const HELP = `cookiejar — local-only cookie bundles for coding agents
72
+
73
+ Usage:
74
+ cookiejar ui [--port ${DEFAULT_PORT}] [--open] [--auto-lock <minutes>]
75
+ Start the local app (127.0.0.1 only) to manage cookies and bundles.
76
+
77
+ cookiejar mcp [--token <token>] [--url ${DEFAULT_URL}]
78
+ Speak MCP over stdio so an agent can use one bundle. Token via
79
+ --token or COOKIEJAR_TOKEN.
80
+
81
+ cookiejar export [--format netscape|storage-state|json] [--out <file>]
82
+ Write a bundle's cookies to a jar file.
83
+
84
+ cookiejar header --url-target <url>
85
+ Print the Cookie header for a URL covered by the bundle.
86
+
87
+ cookiejar doctor
88
+ Show which browser profiles cookiejar can read on this machine.
89
+ `;
90
+ async function main() {
91
+ const args = parseArgs(process.argv.slice(2));
92
+ switch (args.command) {
93
+ case 'ui': {
94
+ const port = Number(flagString(args, 'port', String(DEFAULT_PORT)));
95
+ const autoLock = Number(flagString(args, 'auto-lock', '30'));
96
+ const { url } = await startServer({ port, uiDir: uiDir(), autoLockMinutes: autoLock });
97
+ console.log(`cookiejar is running at ${url}`);
98
+ console.log(`vault: ${process.env.COOKIEJAR_HOME ?? '~/.cookiejar'} · auto-lock: ${autoLock || 'off'}`);
99
+ if (args.flags.get('open'))
100
+ openBrowser(url);
101
+ return;
102
+ }
103
+ case 'mcp': {
104
+ runMcpServer({ daemonUrl: flagString(args, 'url', DEFAULT_URL), token: requireToken(args) });
105
+ return;
106
+ }
107
+ case 'export': {
108
+ const format = flagString(args, 'format', 'netscape');
109
+ const body = await agentGet(args, `/agent/cookies?format=${encodeURIComponent(format)}`);
110
+ const out = flagString(args, 'out');
111
+ if (out) {
112
+ fs.writeFileSync(out, body, { mode: 0o600 });
113
+ console.log(`wrote ${out}`);
114
+ }
115
+ else {
116
+ process.stdout.write(body);
117
+ }
118
+ return;
119
+ }
120
+ case 'header': {
121
+ const target = flagString(args, 'url-target');
122
+ if (!target) {
123
+ console.error('--url-target <url> is required');
124
+ process.exit(2);
125
+ }
126
+ const body = await agentGet(args, `/agent/cookies?format=header&url=${encodeURIComponent(target)}`);
127
+ console.log(JSON.parse(body).cookie);
128
+ return;
129
+ }
130
+ case 'doctor': {
131
+ const reads = readAllProfiles();
132
+ if (reads.length === 0)
133
+ console.log('No browser profiles found.');
134
+ for (const read of reads) {
135
+ const sites = new Set(read.cookies.map((c) => bareDomain(c.domain))).size;
136
+ console.log(read.error
137
+ ? `✗ ${read.profile.label} (${read.profile.id})\n ${read.error}`
138
+ : `✓ ${read.profile.label} (${read.profile.id}) — ${read.cookies.length} cookies across ${sites} sites`);
139
+ }
140
+ return;
141
+ }
142
+ default:
143
+ console.log(HELP);
144
+ process.exit(args.command === 'help' || args.command === '--help' ? 0 : 2);
145
+ }
146
+ }
147
+ void main().catch((error) => {
148
+ console.error(error instanceof Error ? error.message : error);
149
+ process.exit(1);
150
+ });
151
+ //# sourceMappingURL=cli.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,39 @@
1
+ import { audit } from './audit.js';
2
+ import { tokenMatches } from './crypto.js';
3
+ export class AccessDeniedError extends Error {
4
+ }
5
+ /**
6
+ * Resolves a bearer token to the bundle it unlocks. Requires the vault to be
7
+ * unlocked: agent tokens are useless while the jar is closed.
8
+ */
9
+ export function authorize(vault, token) {
10
+ if (!token)
11
+ throw new AccessDeniedError('missing bundle token');
12
+ if (!vault.unlocked)
13
+ throw new AccessDeniedError('cookiejar is locked; unlock it in the app first');
14
+ const now = Date.now() / 1000;
15
+ for (const bundle of vault.read().bundles) {
16
+ for (const grant of bundle.grants) {
17
+ if (!tokenMatches(token, grant.tokenHash))
18
+ continue;
19
+ if (grant.revokedAt)
20
+ throw new AccessDeniedError('this token was revoked');
21
+ if (grant.expiresAt && grant.expiresAt < now)
22
+ throw new AccessDeniedError('this token has expired');
23
+ return { bundle, grant };
24
+ }
25
+ }
26
+ throw new AccessDeniedError('unknown bundle token');
27
+ }
28
+ export function noteUse(vault, grantee, event, detail) {
29
+ vault.write((data) => {
30
+ const bundle = data.bundles.find((b) => b.id === grantee.bundle.id);
31
+ const grant = bundle?.grants.find((g) => g.tokenHash === grantee.grant.tokenHash);
32
+ if (!grant)
33
+ return;
34
+ grant.lastUsedAt = new Date().toISOString();
35
+ grant.useCount += 1;
36
+ });
37
+ audit({ event, bundleId: grantee.bundle.id, grantLabel: grantee.grant.label, detail });
38
+ }
39
+ //# sourceMappingURL=access.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"access.js","sourceRoot":"","sources":["../../src/core/access.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AACnC,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAI3C,MAAM,OAAO,iBAAkB,SAAQ,KAAK;CAAG;AAO/C;;;GAGG;AACH,MAAM,UAAU,SAAS,CAAC,KAAY,EAAE,KAAyB;IAC/D,IAAI,CAAC,KAAK;QAAE,MAAM,IAAI,iBAAiB,CAAC,sBAAsB,CAAC,CAAC;IAChE,IAAI,CAAC,KAAK,CAAC,QAAQ;QAAE,MAAM,IAAI,iBAAiB,CAAC,iDAAiD,CAAC,CAAC;IACpG,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC;IAC9B,KAAK,MAAM,MAAM,IAAI,KAAK,CAAC,IAAI,EAAE,CAAC,OAAO,EAAE,CAAC;QAC1C,KAAK,MAAM,KAAK,IAAI,MAAM,CAAC,MAAM,EAAE,CAAC;YAClC,IAAI,CAAC,YAAY,CAAC,KAAK,EAAE,KAAK,CAAC,SAAS,CAAC;gBAAE,SAAS;YACpD,IAAI,KAAK,CAAC,SAAS;gBAAE,MAAM,IAAI,iBAAiB,CAAC,wBAAwB,CAAC,CAAC;YAC3E,IAAI,KAAK,CAAC,SAAS,IAAI,KAAK,CAAC,SAAS,GAAG,GAAG;gBAAE,MAAM,IAAI,iBAAiB,CAAC,wBAAwB,CAAC,CAAC;YACpG,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC;QAC3B,CAAC;IACH,CAAC;IACD,MAAM,IAAI,iBAAiB,CAAC,sBAAsB,CAAC,CAAC;AACtD,CAAC;AAED,MAAM,UAAU,OAAO,CAAC,KAAY,EAAE,OAAgB,EAAE,KAAqC,EAAE,MAAe;IAC5G,KAAK,CAAC,KAAK,CAAC,CAAC,IAAI,EAAE,EAAE;QACnB,MAAM,MAAM,GAAG,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;QACpE,MAAM,KAAK,GAAG,MAAM,EAAE,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,SAAS,KAAK,OAAO,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC;QAClF,IAAI,CAAC,KAAK;YAAE,OAAO;QACnB,KAAK,CAAC,UAAU,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;QAC5C,KAAK,CAAC,QAAQ,IAAI,CAAC,CAAC;IACtB,CAAC,CAAC,CAAC;IACH,KAAK,CAAC,EAAE,KAAK,EAAE,QAAQ,EAAE,OAAO,CAAC,MAAM,CAAC,EAAE,EAAE,UAAU,EAAE,OAAO,CAAC,KAAK,CAAC,KAAK,EAAE,MAAM,EAAE,CAAC,CAAC;AACzF,CAAC"}
@@ -0,0 +1,26 @@
1
+ import fs from 'node:fs';
2
+ import { auditPath, ensureConfigDir } from './paths.js';
3
+ /** Append-only local log of every access. Cookie values are never recorded. */
4
+ export function audit(entry) {
5
+ ensureConfigDir();
6
+ fs.appendFileSync(auditPath(), `${JSON.stringify({ at: new Date().toISOString(), ...entry })}\n`, { mode: 0o600 });
7
+ }
8
+ export function readAudit(limit = 200) {
9
+ if (!fs.existsSync(auditPath()))
10
+ return [];
11
+ return fs
12
+ .readFileSync(auditPath(), 'utf8')
13
+ .split('\n')
14
+ .filter(Boolean)
15
+ .slice(-limit)
16
+ .reverse()
17
+ .flatMap((line) => {
18
+ try {
19
+ return [JSON.parse(line)];
20
+ }
21
+ catch {
22
+ return [];
23
+ }
24
+ });
25
+ }
26
+ //# sourceMappingURL=audit.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"audit.js","sourceRoot":"","sources":["../../src/core/audit.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,EAAE,SAAS,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAGxD,+EAA+E;AAC/E,MAAM,UAAU,KAAK,CAAC,KAA6B;IACjD,eAAe,EAAE,CAAC;IAClB,EAAE,CAAC,cAAc,CAAC,SAAS,EAAE,EAAE,GAAG,IAAI,CAAC,SAAS,CAAC,EAAE,EAAE,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,EAAE,GAAG,KAAK,EAAE,CAAC,IAAI,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;AACrH,CAAC;AAED,MAAM,UAAU,SAAS,CAAC,KAAK,GAAG,GAAG;IACnC,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,SAAS,EAAE,CAAC;QAAE,OAAO,EAAE,CAAC;IAC3C,OAAO,EAAE;SACN,YAAY,CAAC,SAAS,EAAE,EAAE,MAAM,CAAC;SACjC,KAAK,CAAC,IAAI,CAAC;SACX,MAAM,CAAC,OAAO,CAAC;SACf,KAAK,CAAC,CAAC,KAAK,CAAC;SACb,OAAO,EAAE;SACT,OAAO,CAAC,CAAC,IAAI,EAAE,EAAE;QAChB,IAAI,CAAC;YACH,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAe,CAAC,CAAC;QAC1C,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,EAAE,CAAC;QACZ,CAAC;IACH,CAAC,CAAC,CAAC;AACP,CAAC"}
@@ -0,0 +1,241 @@
1
+ import fs from 'node:fs';
2
+ import path from 'node:path';
3
+ import os from 'node:os';
4
+ import crypto from 'node:crypto';
5
+ import { execFileSync } from 'node:child_process';
6
+ import { webkitToUnix, withCookieDb } from './sqlite.js';
7
+ const FLAVOURS = [
8
+ {
9
+ browser: 'chrome',
10
+ label: 'Chrome',
11
+ dirs: { darwin: 'Library/Application Support/Google/Chrome', linux: '.config/google-chrome' },
12
+ keychainService: 'Chrome Safe Storage',
13
+ linuxKeyringApp: 'chrome',
14
+ },
15
+ {
16
+ browser: 'chrome-beta',
17
+ label: 'Chrome Beta',
18
+ dirs: { darwin: 'Library/Application Support/Google/Chrome Beta', linux: '.config/google-chrome-beta' },
19
+ keychainService: 'Chrome Safe Storage',
20
+ linuxKeyringApp: 'chrome',
21
+ },
22
+ {
23
+ browser: 'chromium',
24
+ label: 'Chromium',
25
+ dirs: { darwin: 'Library/Application Support/Chromium', linux: '.config/chromium' },
26
+ keychainService: 'Chromium Safe Storage',
27
+ linuxKeyringApp: 'chromium',
28
+ },
29
+ {
30
+ browser: 'brave',
31
+ label: 'Brave',
32
+ dirs: {
33
+ darwin: 'Library/Application Support/BraveSoftware/Brave-Browser',
34
+ linux: '.config/BraveSoftware/Brave-Browser',
35
+ },
36
+ keychainService: 'Brave Safe Storage',
37
+ linuxKeyringApp: 'brave',
38
+ },
39
+ {
40
+ browser: 'edge',
41
+ label: 'Edge',
42
+ dirs: { darwin: 'Library/Application Support/Microsoft Edge', linux: '.config/microsoft-edge' },
43
+ keychainService: 'Microsoft Edge Safe Storage',
44
+ linuxKeyringApp: 'chromium',
45
+ },
46
+ {
47
+ browser: 'arc',
48
+ label: 'Arc',
49
+ dirs: { darwin: 'Library/Application Support/Arc/User Data' },
50
+ keychainService: 'Arc Safe Storage',
51
+ linuxKeyringApp: 'chromium',
52
+ },
53
+ ];
54
+ function userDataDir(flavour) {
55
+ const rel = process.platform === 'darwin' ? flavour.dirs.darwin : flavour.dirs.linux;
56
+ if (!rel)
57
+ return null;
58
+ const dir = path.join(os.homedir(), rel);
59
+ return fs.existsSync(dir) ? dir : null;
60
+ }
61
+ function profileNames(userDir) {
62
+ const names = new Map();
63
+ try {
64
+ const state = JSON.parse(fs.readFileSync(path.join(userDir, 'Local State'), 'utf8'));
65
+ for (const [dir, info] of Object.entries(state.profile?.info_cache ?? {})) {
66
+ if (info.name)
67
+ names.set(dir, info.name);
68
+ }
69
+ }
70
+ catch {
71
+ // A missing or half-written Local State just costs us pretty profile names.
72
+ }
73
+ return names;
74
+ }
75
+ export function discoverChromiumProfiles() {
76
+ const profiles = [];
77
+ for (const flavour of FLAVOURS) {
78
+ const userDir = userDataDir(flavour);
79
+ if (!userDir)
80
+ continue;
81
+ const pretty = profileNames(userDir);
82
+ for (const entry of fs.readdirSync(userDir, { withFileTypes: true })) {
83
+ if (!entry.isDirectory())
84
+ continue;
85
+ const cookies = [
86
+ path.join(userDir, entry.name, 'Cookies'),
87
+ path.join(userDir, entry.name, 'Network', 'Cookies'),
88
+ ].find((p) => fs.existsSync(p));
89
+ if (!cookies)
90
+ continue;
91
+ profiles.push({
92
+ browser: flavour.browser,
93
+ id: `${flavour.browser}:${entry.name}`,
94
+ label: `${flavour.label} — ${pretty.get(entry.name) ?? entry.name}`,
95
+ path: cookies,
96
+ });
97
+ }
98
+ }
99
+ return profiles;
100
+ }
101
+ function keychainPassword(service) {
102
+ try {
103
+ return execFileSync('security', ['find-generic-password', '-w', '-s', service], {
104
+ encoding: 'utf8',
105
+ stdio: ['ignore', 'pipe', 'ignore'],
106
+ }).trim();
107
+ }
108
+ catch {
109
+ return null;
110
+ }
111
+ }
112
+ function linuxKeyringPassword(app) {
113
+ for (const args of [
114
+ ['lookup', 'application', app],
115
+ ['lookup', 'application', 'chrome'],
116
+ ]) {
117
+ try {
118
+ const out = execFileSync('secret-tool', args, { encoding: 'utf8', stdio: ['ignore', 'pipe', 'ignore'] });
119
+ if (out)
120
+ return out.trim();
121
+ }
122
+ catch {
123
+ // secret-tool missing or the entry is absent; fall through to "peanuts".
124
+ }
125
+ }
126
+ return null;
127
+ }
128
+ /** Chromium derives its AES key from a password with fixed, published parameters. */
129
+ function legacyKey(password, iterations) {
130
+ return crypto.pbkdf2Sync(password, 'saltysalt', iterations, 16, 'sha1');
131
+ }
132
+ function keyringFor(flavour) {
133
+ if (process.platform === 'darwin') {
134
+ const password = keychainPassword(flavour.keychainService);
135
+ return { cbcKeys: password ? [legacyKey(password, 1003)] : [], gcmKey: null };
136
+ }
137
+ const keys = [legacyKey('peanuts', 1)];
138
+ const fromKeyring = linuxKeyringPassword(flavour.linuxKeyringApp);
139
+ if (fromKeyring)
140
+ keys.unshift(legacyKey(fromKeyring, 1));
141
+ return { cbcKeys: keys, gcmKey: null };
142
+ }
143
+ export class UnavailableKeyError extends Error {
144
+ }
145
+ /**
146
+ * Recent Chrome versions bind a cookie to its host by prefixing the plaintext
147
+ * with sha256(host_key), so strip that prefix when it is really there.
148
+ */
149
+ function stripDomainPrefix(plaintext, host) {
150
+ if (plaintext.length <= 32)
151
+ return plaintext;
152
+ const prefix = plaintext.subarray(0, 32);
153
+ for (const candidate of host ? [host, host.replace(/^\./, '')] : []) {
154
+ if (crypto.createHash('sha256').update(candidate).digest().equals(prefix))
155
+ return plaintext.subarray(32);
156
+ }
157
+ // Unknown hash: fall back to "a value would not contain control bytes".
158
+ return prefix.some((byte) => byte < 0x20) ? plaintext.subarray(32) : plaintext;
159
+ }
160
+ function decryptCbc(blob, key, host) {
161
+ const iv = Buffer.alloc(16, 0x20);
162
+ const decipher = crypto.createDecipheriv('aes-128-cbc', key, iv);
163
+ const out = Buffer.concat([decipher.update(blob), decipher.final()]);
164
+ return stripDomainPrefix(out, host).toString('utf8');
165
+ }
166
+ function decryptGcm(blob, key, host) {
167
+ const nonce = blob.subarray(0, 12);
168
+ const tag = blob.subarray(blob.length - 16);
169
+ const decipher = crypto.createDecipheriv('aes-256-gcm', key, nonce);
170
+ decipher.setAuthTag(tag);
171
+ const out = Buffer.concat([decipher.update(blob.subarray(12, blob.length - 16)), decipher.final()]);
172
+ return stripDomainPrefix(out, host).toString('utf8');
173
+ }
174
+ export function decryptChromiumValue(encrypted, plain, keyring, host) {
175
+ if (plain)
176
+ return plain;
177
+ if (encrypted.length === 0)
178
+ return '';
179
+ const version = encrypted.subarray(0, 3).toString('latin1');
180
+ const body = encrypted.subarray(3);
181
+ if (version === 'v20') {
182
+ // App-bound encryption (Windows only); the key lives behind an elevation service.
183
+ throw new UnavailableKeyError('app-bound encrypted cookie (v20) is not supported');
184
+ }
185
+ if (version === 'v10' || version === 'v11') {
186
+ if (keyring.gcmKey)
187
+ return decryptGcm(body, keyring.gcmKey, host);
188
+ let lastError;
189
+ for (const key of keyring.cbcKeys) {
190
+ try {
191
+ return decryptCbc(body, key, host);
192
+ }
193
+ catch (error) {
194
+ lastError = error;
195
+ }
196
+ }
197
+ if (keyring.cbcKeys.length === 0)
198
+ throw new UnavailableKeyError('no decryption key available for this browser');
199
+ throw lastError instanceof Error ? lastError : new Error('failed to decrypt cookie');
200
+ }
201
+ return encrypted.toString('utf8');
202
+ }
203
+ const sameSiteFromChromium = (value) => value === 0 ? 'None' : value === 1 ? 'Lax' : value === 2 ? 'Strict' : 'Unspecified';
204
+ export function readChromiumCookies(profile) {
205
+ const flavour = FLAVOURS.find((f) => f.browser === profile.browser);
206
+ if (!flavour)
207
+ throw new Error(`unknown chromium flavour: ${profile.browser}`);
208
+ const keyring = keyringFor(flavour);
209
+ return withCookieDb(profile.path, (db) => {
210
+ const statement = db.prepare(`SELECT host_key, name, value, encrypted_value, path, expires_utc, is_secure, is_httponly, samesite
211
+ FROM cookies ORDER BY host_key, name`);
212
+ // Chromium expiry timestamps overflow a JS number, so read integers as BigInt.
213
+ statement.setReadBigInts(true);
214
+ const rows = statement.all();
215
+ const cookies = [];
216
+ for (const row of rows) {
217
+ const encrypted = row.encrypted_value instanceof Uint8Array ? Buffer.from(row.encrypted_value) : Buffer.alloc(0);
218
+ let value;
219
+ try {
220
+ value = decryptChromiumValue(encrypted, String(row.value ?? ''), keyring, String(row.host_key ?? ''));
221
+ }
222
+ catch {
223
+ continue; // Skip cookies we cannot read rather than failing the whole profile.
224
+ }
225
+ cookies.push({
226
+ name: String(row.name),
227
+ value,
228
+ domain: String(row.host_key),
229
+ path: String(row.path ?? '/'),
230
+ expires: webkitToUnix(row.expires_utc),
231
+ secure: Boolean(row.is_secure),
232
+ httpOnly: Boolean(row.is_httponly),
233
+ sameSite: sameSiteFromChromium(Number(row.samesite ?? -1)),
234
+ profileId: profile.id,
235
+ browser: profile.browser,
236
+ });
237
+ }
238
+ return cookies;
239
+ });
240
+ }
241
+ //# sourceMappingURL=chromium.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"chromium.js","sourceRoot":"","sources":["../../../src/core/browsers/chromium.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,MAAM,MAAM,aAAa,CAAC;AACjC,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAczD,MAAM,QAAQ,GAAsB;IAClC;QACE,OAAO,EAAE,QAAQ;QACjB,KAAK,EAAE,QAAQ;QACf,IAAI,EAAE,EAAE,MAAM,EAAE,2CAA2C,EAAE,KAAK,EAAE,uBAAuB,EAAE;QAC7F,eAAe,EAAE,qBAAqB;QACtC,eAAe,EAAE,QAAQ;KAC1B;IACD;QACE,OAAO,EAAE,aAAa;QACtB,KAAK,EAAE,aAAa;QACpB,IAAI,EAAE,EAAE,MAAM,EAAE,gDAAgD,EAAE,KAAK,EAAE,4BAA4B,EAAE;QACvG,eAAe,EAAE,qBAAqB;QACtC,eAAe,EAAE,QAAQ;KAC1B;IACD;QACE,OAAO,EAAE,UAAU;QACnB,KAAK,EAAE,UAAU;QACjB,IAAI,EAAE,EAAE,MAAM,EAAE,sCAAsC,EAAE,KAAK,EAAE,kBAAkB,EAAE;QACnF,eAAe,EAAE,uBAAuB;QACxC,eAAe,EAAE,UAAU;KAC5B;IACD;QACE,OAAO,EAAE,OAAO;QAChB,KAAK,EAAE,OAAO;QACd,IAAI,EAAE;YACJ,MAAM,EAAE,yDAAyD;YACjE,KAAK,EAAE,qCAAqC;SAC7C;QACD,eAAe,EAAE,oBAAoB;QACrC,eAAe,EAAE,OAAO;KACzB;IACD;QACE,OAAO,EAAE,MAAM;QACf,KAAK,EAAE,MAAM;QACb,IAAI,EAAE,EAAE,MAAM,EAAE,4CAA4C,EAAE,KAAK,EAAE,wBAAwB,EAAE;QAC/F,eAAe,EAAE,6BAA6B;QAC9C,eAAe,EAAE,UAAU;KAC5B;IACD;QACE,OAAO,EAAE,KAAK;QACd,KAAK,EAAE,KAAK;QACZ,IAAI,EAAE,EAAE,MAAM,EAAE,2CAA2C,EAAE;QAC7D,eAAe,EAAE,kBAAkB;QACnC,eAAe,EAAE,UAAU;KAC5B;CACF,CAAC;AAEF,SAAS,WAAW,CAAC,OAAwB;IAC3C,MAAM,GAAG,GAAG,OAAO,CAAC,QAAQ,KAAK,QAAQ,CAAC,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC;IACrF,IAAI,CAAC,GAAG;QAAE,OAAO,IAAI,CAAC;IACtB,MAAM,GAAG,GAAG,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,EAAE,GAAG,CAAC,CAAC;IACzC,OAAO,EAAE,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC;AACzC,CAAC;AAED,SAAS,YAAY,CAAC,OAAe;IACnC,MAAM,KAAK,GAAG,IAAI,GAAG,EAAkB,CAAC;IACxC,IAAI,CAAC;QACH,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,aAAa,CAAC,EAAE,MAAM,CAAC,CAElF,CAAC;QACF,KAAK,MAAM,CAAC,GAAG,EAAE,IAAI,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,OAAO,EAAE,UAAU,IAAI,EAAE,CAAC,EAAE,CAAC;YAC1E,IAAI,IAAI,CAAC,IAAI;gBAAE,KAAK,CAAC,GAAG,CAAC,GAAG,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC;QAC3C,CAAC;IACH,CAAC;IAAC,MAAM,CAAC;QACP,4EAA4E;IAC9E,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED,MAAM,UAAU,wBAAwB;IACtC,MAAM,QAAQ,GAAqB,EAAE,CAAC;IACtC,KAAK,MAAM,OAAO,IAAI,QAAQ,EAAE,CAAC;QAC/B,MAAM,OAAO,GAAG,WAAW,CAAC,OAAO,CAAC,CAAC;QACrC,IAAI,CAAC,OAAO;YAAE,SAAS;QACvB,MAAM,MAAM,GAAG,YAAY,CAAC,OAAO,CAAC,CAAC;QACrC,KAAK,MAAM,KAAK,IAAI,EAAE,CAAC,WAAW,CAAC,OAAO,EAAE,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC,EAAE,CAAC;YACrE,IAAI,CAAC,KAAK,CAAC,WAAW,EAAE;gBAAE,SAAS;YACnC,MAAM,OAAO,GAAG;gBACd,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,KAAK,CAAC,IAAI,EAAE,SAAS,CAAC;gBACzC,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,KAAK,CAAC,IAAI,EAAE,SAAS,EAAE,SAAS,CAAC;aACrD,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,EAAE,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC;YAChC,IAAI,CAAC,OAAO;gBAAE,SAAS;YACvB,QAAQ,CAAC,IAAI,CAAC;gBACZ,OAAO,EAAE,OAAO,CAAC,OAAO;gBACxB,EAAE,EAAE,GAAG,OAAO,CAAC,OAAO,IAAI,KAAK,CAAC,IAAI,EAAE;gBACtC,KAAK,EAAE,GAAG,OAAO,CAAC,KAAK,MAAM,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,KAAK,CAAC,IAAI,EAAE;gBACnE,IAAI,EAAE,OAAO;aACd,CAAC,CAAC;QACL,CAAC;IACH,CAAC;IACD,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED,SAAS,gBAAgB,CAAC,OAAe;IACvC,IAAI,CAAC;QACH,OAAO,YAAY,CAAC,UAAU,EAAE,CAAC,uBAAuB,EAAE,IAAI,EAAE,IAAI,EAAE,OAAO,CAAC,EAAE;YAC9E,QAAQ,EAAE,MAAM;YAChB,KAAK,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,CAAC;SACpC,CAAC,CAAC,IAAI,EAAE,CAAC;IACZ,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED,SAAS,oBAAoB,CAAC,GAAW;IACvC,KAAK,MAAM,IAAI,IAAI;QACjB,CAAC,QAAQ,EAAE,aAAa,EAAE,GAAG,CAAC;QAC9B,CAAC,QAAQ,EAAE,aAAa,EAAE,QAAQ,CAAC;KACpC,EAAE,CAAC;QACF,IAAI,CAAC;YACH,MAAM,GAAG,GAAG,YAAY,CAAC,aAAa,EAAE,IAAI,EAAE,EAAE,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,CAAC,CAAC;YACzG,IAAI,GAAG;gBAAE,OAAO,GAAG,CAAC,IAAI,EAAE,CAAC;QAC7B,CAAC;QAAC,MAAM,CAAC;YACP,yEAAyE;QAC3E,CAAC;IACH,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED,qFAAqF;AACrF,SAAS,SAAS,CAAC,QAAgB,EAAE,UAAkB;IACrD,OAAO,MAAM,CAAC,UAAU,CAAC,QAAQ,EAAE,WAAW,EAAE,UAAU,EAAE,EAAE,EAAE,MAAM,CAAC,CAAC;AAC1E,CAAC;AASD,SAAS,UAAU,CAAC,OAAwB;IAC1C,IAAI,OAAO,CAAC,QAAQ,KAAK,QAAQ,EAAE,CAAC;QAClC,MAAM,QAAQ,GAAG,gBAAgB,CAAC,OAAO,CAAC,eAAe,CAAC,CAAC;QAC3D,OAAO,EAAE,OAAO,EAAE,QAAQ,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC;IAChF,CAAC;IACD,MAAM,IAAI,GAAG,CAAC,SAAS,CAAC,SAAS,EAAE,CAAC,CAAC,CAAC,CAAC;IACvC,MAAM,WAAW,GAAG,oBAAoB,CAAC,OAAO,CAAC,eAAe,CAAC,CAAC;IAClE,IAAI,WAAW;QAAE,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC,CAAC;IACzD,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC;AACzC,CAAC;AAED,MAAM,OAAO,mBAAoB,SAAQ,KAAK;CAAG;AAEjD;;;GAGG;AACH,SAAS,iBAAiB,CAAC,SAAiB,EAAE,IAAwB;IACpE,IAAI,SAAS,CAAC,MAAM,IAAI,EAAE;QAAE,OAAO,SAAS,CAAC;IAC7C,MAAM,MAAM,GAAG,SAAS,CAAC,QAAQ,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;IACzC,KAAK,MAAM,SAAS,IAAI,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC;QACpE,IAAI,MAAM,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,MAAM,EAAE,CAAC,MAAM,CAAC,MAAM,CAAC;YAAE,OAAO,SAAS,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;IAC3G,CAAC;IACD,wEAAwE;IACxE,OAAO,MAAM,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;AACjF,CAAC;AAED,SAAS,UAAU,CAAC,IAAY,EAAE,GAAW,EAAE,IAAwB;IACrE,MAAM,EAAE,GAAG,MAAM,CAAC,KAAK,CAAC,EAAE,EAAE,IAAI,CAAC,CAAC;IAClC,MAAM,QAAQ,GAAG,MAAM,CAAC,gBAAgB,CAAC,aAAa,EAAE,GAAG,EAAE,EAAE,CAAC,CAAC;IACjE,MAAM,GAAG,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,QAAQ,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC;IACrE,OAAO,iBAAiB,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;AACvD,CAAC;AAED,SAAS,UAAU,CAAC,IAAY,EAAE,GAAW,EAAE,IAAwB;IACrE,MAAM,KAAK,GAAG,IAAI,CAAC,QAAQ,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;IACnC,MAAM,GAAG,GAAG,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,MAAM,GAAG,EAAE,CAAC,CAAC;IAC5C,MAAM,QAAQ,GAAG,MAAM,CAAC,gBAAgB,CAAC,aAAa,EAAE,GAAG,EAAE,KAAK,CAAC,CAAC;IACpE,QAAQ,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC;IACzB,MAAM,GAAG,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,IAAI,CAAC,MAAM,GAAG,EAAE,CAAC,CAAC,EAAE,QAAQ,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC;IACpG,OAAO,iBAAiB,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;AACvD,CAAC;AAED,MAAM,UAAU,oBAAoB,CAAC,SAAiB,EAAE,KAAa,EAAE,OAAgB,EAAE,IAAa;IACpG,IAAI,KAAK;QAAE,OAAO,KAAK,CAAC;IACxB,IAAI,SAAS,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,EAAE,CAAC;IACtC,MAAM,OAAO,GAAG,SAAS,CAAC,QAAQ,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;IAC5D,MAAM,IAAI,GAAG,SAAS,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;IACnC,IAAI,OAAO,KAAK,KAAK,EAAE,CAAC;QACtB,kFAAkF;QAClF,MAAM,IAAI,mBAAmB,CAAC,mDAAmD,CAAC,CAAC;IACrF,CAAC;IACD,IAAI,OAAO,KAAK,KAAK,IAAI,OAAO,KAAK,KAAK,EAAE,CAAC;QAC3C,IAAI,OAAO,CAAC,MAAM;YAAE,OAAO,UAAU,CAAC,IAAI,EAAE,OAAO,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;QAClE,IAAI,SAAkB,CAAC;QACvB,KAAK,MAAM,GAAG,IAAI,OAAO,CAAC,OAAO,EAAE,CAAC;YAClC,IAAI,CAAC;gBACH,OAAO,UAAU,CAAC,IAAI,EAAE,GAAG,EAAE,IAAI,CAAC,CAAC;YACrC,CAAC;YAAC,OAAO,KAAK,EAAE,CAAC;gBACf,SAAS,GAAG,KAAK,CAAC;YACpB,CAAC;QACH,CAAC;QACD,IAAI,OAAO,CAAC,OAAO,CAAC,MAAM,KAAK,CAAC;YAAE,MAAM,IAAI,mBAAmB,CAAC,8CAA8C,CAAC,CAAC;QAChH,MAAM,SAAS,YAAY,KAAK,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC,0BAA0B,CAAC,CAAC;IACvF,CAAC;IACD,OAAO,SAAS,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;AACpC,CAAC;AAED,MAAM,oBAAoB,GAAG,CAAC,KAAa,EAA6B,EAAE,CACxE,KAAK,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,KAAK,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,aAAa,CAAC;AAEtF,MAAM,UAAU,mBAAmB,CAAC,OAAuB;IACzD,MAAM,OAAO,GAAG,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;IACpE,IAAI,CAAC,OAAO;QAAE,MAAM,IAAI,KAAK,CAAC,6BAA6B,OAAO,CAAC,OAAO,EAAE,CAAC,CAAC;IAC9E,MAAM,OAAO,GAAG,UAAU,CAAC,OAAO,CAAC,CAAC;IAEpC,OAAO,YAAY,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC,EAAE,EAAE,EAAE;QACvC,MAAM,SAAS,GAAG,EAAE,CAAC,OAAO,CAC1B;4CACsC,CACvC,CAAC;QACF,+EAA+E;QAC/E,SAAS,CAAC,cAAc,CAAC,IAAI,CAAC,CAAC;QAC/B,MAAM,IAAI,GAAG,SAAS,CAAC,GAAG,EAAoC,CAAC;QAE/D,MAAM,OAAO,GAAoB,EAAE,CAAC;QACpC,KAAK,MAAM,GAAG,IAAI,IAAI,EAAE,CAAC;YACvB,MAAM,SAAS,GAAG,GAAG,CAAC,eAAe,YAAY,UAAU,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;YACjH,IAAI,KAAa,CAAC;YAClB,IAAI,CAAC;gBACH,KAAK,GAAG,oBAAoB,CAAC,SAAS,EAAE,MAAM,CAAC,GAAG,CAAC,KAAK,IAAI,EAAE,CAAC,EAAE,OAAO,EAAE,MAAM,CAAC,GAAG,CAAC,QAAQ,IAAI,EAAE,CAAC,CAAC,CAAC;YACxG,CAAC;YAAC,MAAM,CAAC;gBACP,SAAS,CAAC,qEAAqE;YACjF,CAAC;YACD,OAAO,CAAC,IAAI,CAAC;gBACX,IAAI,EAAE,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC;gBACtB,KAAK;gBACL,MAAM,EAAE,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC;gBAC5B,IAAI,EAAE,MAAM,CAAC,GAAG,CAAC,IAAI,IAAI,GAAG,CAAC;gBAC7B,OAAO,EAAE,YAAY,CAAC,GAAG,CAAC,WAAqB,CAAC;gBAChD,MAAM,EAAE,OAAO,CAAC,GAAG,CAAC,SAAS,CAAC;gBAC9B,QAAQ,EAAE,OAAO,CAAC,GAAG,CAAC,WAAW,CAAC;gBAClC,QAAQ,EAAE,oBAAoB,CAAC,MAAM,CAAC,GAAG,CAAC,QAAQ,IAAI,CAAC,CAAC,CAAC,CAAC;gBAC1D,SAAS,EAAE,OAAO,CAAC,EAAE;gBACrB,OAAO,EAAE,OAAO,CAAC,OAAO;aACzB,CAAC,CAAC;QACL,CAAC;QACD,OAAO,OAAO,CAAC;IACjB,CAAC,CAAC,CAAC;AACL,CAAC"}