@aloth/olcli 0.15.3 → 0.16.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.
@@ -0,0 +1,144 @@
1
+ /**
2
+ * `olcli auth --browser`: sign in through a real browser window and keep only
3
+ * the session cookie.
4
+ *
5
+ * Copying a cookie out of the developer tools is the hardest step of the first
6
+ * run, and SSO, ORCID, Google and two-factor logins have no other path. So
7
+ * olcli starts the installed Chrome, Edge, Chromium or Brave with a fresh
8
+ * temporary profile (never the user's own), opens the instance's login page,
9
+ * and watches the cookie jar of that profile over the Chrome DevTools Protocol
10
+ * until a session cookie appears that Overleaf accepts for the project list.
11
+ *
12
+ * What olcli sees: only the cookies the browser would send to the instance
13
+ * URL, and of those only the session cookie is kept. It never sees a form
14
+ * field or a password; the user types those into the browser, not into olcli.
15
+ *
16
+ * No dependency: the protocol is JSON over a WebSocket, and Node 22 ships a
17
+ * WebSocket client. The browser process and its profile directory are removed
18
+ * on success, error, timeout and Ctrl-C.
19
+ */
20
+ /** How long `auth --browser` waits for the user to finish signing in. */
21
+ export declare const BROWSER_SIGN_IN_TIMEOUT_MS: number;
22
+ /** Session cookie names olcli knows, in addition to the configured one. */
23
+ export declare const KNOWN_SESSION_COOKIES: string[];
24
+ export declare class BrowserNotFoundError extends Error {
25
+ constructor(message: string);
26
+ }
27
+ export interface BrowserLookup {
28
+ env?: NodeJS.ProcessEnv;
29
+ platform?: NodeJS.Platform;
30
+ home?: string;
31
+ /** True when `path` is an existing file (or, for an .app, directory). */
32
+ exists?: (path: string) => boolean;
33
+ /** Contents of a text file, or undefined. Used for Info.plist. */
34
+ readText?: (path: string) => string | undefined;
35
+ }
36
+ export interface FoundBrowser {
37
+ /** The executable to start. */
38
+ path: string;
39
+ /** A name for messages, like "Google Chrome". */
40
+ name: string;
41
+ }
42
+ /**
43
+ * The executable inside a macOS .app bundle: CFBundleExecutable from
44
+ * Info.plist when it is readable as XML, else the bundle name without ".app".
45
+ */
46
+ export declare function appBundleExecutable(appPath: string, readText?: (path: string) => string | undefined): string;
47
+ /**
48
+ * The browser to start. OLCLI_BROWSER first (an executable, or on macOS an
49
+ * .app bundle), then the usual install locations of Chrome, Chromium, Edge
50
+ * and Brave for the platform.
51
+ */
52
+ export declare function findBrowser(lookup?: BrowserLookup): FoundBrowser;
53
+ /** The fields of a CDP Network.Cookie that matter here. */
54
+ export interface BrowserCookie {
55
+ name: string;
56
+ value: string;
57
+ domain: string;
58
+ }
59
+ export interface SessionCookie {
60
+ name: string;
61
+ value: string;
62
+ }
63
+ /**
64
+ * The session cookie among `cookies`, or undefined. Only a cookie for the
65
+ * instance's host whose name is the configured one or one of the known
66
+ * session cookie names is taken; everything else is ignored, so no other
67
+ * cookie ever leaves this function. The configured name wins over the others.
68
+ */
69
+ export declare function pickSessionCookie(cookies: BrowserCookie[], baseUrl: string, preferredName: string): SessionCookie | undefined;
70
+ /** The part of the DevTools Protocol olcli uses. Faked in tests. */
71
+ export interface CdpTransport {
72
+ send(method: string, params?: Record<string, unknown>, sessionId?: string): Promise<any>;
73
+ close(): void;
74
+ }
75
+ /** A started browser: its protocol connection and how to stop it. */
76
+ export interface RunningBrowser {
77
+ cdp: CdpTransport;
78
+ /** Resolves when the browser process exits, for whatever reason. */
79
+ exited: Promise<void>;
80
+ /** Close the browser; kills it if it does not exit by itself. */
81
+ stop(): Promise<void>;
82
+ }
83
+ export type StartBrowser = (profileDir: string, url: string, signal: AbortSignal) => Promise<RunningBrowser>;
84
+ export declare class BrowserSignInError extends Error {
85
+ constructor(message: string);
86
+ }
87
+ export declare class BrowserSignInAborted extends Error {
88
+ constructor();
89
+ }
90
+ /** Node's WebSocket, or a clear error on Node 20 and 21, which do not ship one. */
91
+ export declare function requireWebSocket(): typeof WebSocket;
92
+ /** A CdpTransport over a WebSocket to the browser endpoint. */
93
+ export declare function connectCdp(endpoint: string): Promise<CdpTransport>;
94
+ /** Command-line arguments for a throwaway browser session. */
95
+ export declare function browserArgs(profileDir: string, url: string): string[];
96
+ /**
97
+ * `promise`, but rejected with BrowserSignInAborted when `signal` fires and
98
+ * with a BrowserSignInError after `ms`. A protocol call to a busy or hung
99
+ * browser can stay unanswered; without this, Ctrl-C would wait for it.
100
+ */
101
+ export declare function guarded<T>(promise: Promise<T>, signal: AbortSignal, ms: number, what: string): Promise<T>;
102
+ /**
103
+ * The real StartBrowser: spawn `executable`, wait for it to write
104
+ * DevToolsActivePort into the profile, then connect to the browser endpoint.
105
+ * `--remote-debugging-port=0` lets the browser pick a free port.
106
+ */
107
+ export declare function chromiumLauncher(executable: string): StartBrowser;
108
+ export interface BrowserSignInOptions {
109
+ baseUrl: string;
110
+ /** The configured session cookie name. */
111
+ cookieName: string;
112
+ startBrowser: StartBrowser;
113
+ /**
114
+ * True when Overleaf accepts the cookie for the project list. Errors count
115
+ * as "not yet": before the login, the instance already sets an anonymous
116
+ * session cookie under the same name.
117
+ */
118
+ validate: (cookie: SessionCookie) => Promise<boolean>;
119
+ timeoutMs?: number;
120
+ pollMs?: number;
121
+ /** How often an unchanged session cookie is checked against Overleaf again. */
122
+ recheckMs?: number;
123
+ signal?: AbortSignal;
124
+ /** Where the temporary profile goes; os.tmpdir() by default. */
125
+ tmpRoot?: string;
126
+ /** Called with the profile directory once it exists. */
127
+ onProfile?: (profileDir: string) => void;
128
+ }
129
+ /**
130
+ * An unchanged cookie is validated against the instance at most this often.
131
+ * A new cookie value is validated at once, so a login that replaces the
132
+ * session id is picked up within a second; one that keeps it within 7 s.
133
+ * Over the 5-minute wait that is at most about 43 project-list requests.
134
+ */
135
+ export declare const BROWSER_SIGN_IN_RECHECK_MS = 7000;
136
+ /**
137
+ * Open `<baseUrl>/login` in a throwaway browser profile and wait until the
138
+ * profile holds a session cookie that `validate` accepts. Returns that cookie
139
+ * only. The browser is closed and the profile deleted on every way out.
140
+ */
141
+ export declare function browserSignIn(options: BrowserSignInOptions): Promise<SessionCookie>;
142
+ /** Delete a temporary profile. Retries, since the browser may still be writing. */
143
+ export declare function removeProfile(profileDir: string): void;
144
+ //# sourceMappingURL=browser-auth.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"browser-auth.d.ts","sourceRoot":"","sources":["../src/browser-auth.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,442 @@
1
+ /**
2
+ * `olcli auth --browser`: sign in through a real browser window and keep only
3
+ * the session cookie.
4
+ *
5
+ * Copying a cookie out of the developer tools is the hardest step of the first
6
+ * run, and SSO, ORCID, Google and two-factor logins have no other path. So
7
+ * olcli starts the installed Chrome, Edge, Chromium or Brave with a fresh
8
+ * temporary profile (never the user's own), opens the instance's login page,
9
+ * and watches the cookie jar of that profile over the Chrome DevTools Protocol
10
+ * until a session cookie appears that Overleaf accepts for the project list.
11
+ *
12
+ * What olcli sees: only the cookies the browser would send to the instance
13
+ * URL, and of those only the session cookie is kept. It never sees a form
14
+ * field or a password; the user types those into the browser, not into olcli.
15
+ *
16
+ * No dependency: the protocol is JSON over a WebSocket, and Node 22 ships a
17
+ * WebSocket client. The browser process and its profile directory are removed
18
+ * on success, error, timeout and Ctrl-C.
19
+ */
20
+ import { spawn } from 'node:child_process';
21
+ import { existsSync, mkdtempSync, readFileSync, rmSync, statSync } from 'node:fs';
22
+ import { tmpdir, homedir } from 'node:os';
23
+ import { basename, delimiter, join } from 'node:path';
24
+ /** How long `auth --browser` waits for the user to finish signing in. */
25
+ export const BROWSER_SIGN_IN_TIMEOUT_MS = 5 * 60 * 1000;
26
+ /** Session cookie names olcli knows, in addition to the configured one. */
27
+ export const KNOWN_SESSION_COOKIES = ['overleaf_session2', 'overleaf.sid'];
28
+ // ─────────────────────────────────────────────────────────────────────────────
29
+ // Finding a browser
30
+ // ─────────────────────────────────────────────────────────────────────────────
31
+ export class BrowserNotFoundError extends Error {
32
+ constructor(message) {
33
+ super(message);
34
+ this.name = 'BrowserNotFoundError';
35
+ }
36
+ }
37
+ const MAC_APPS = ['Google Chrome', 'Chromium', 'Microsoft Edge', 'Brave Browser'];
38
+ const LINUX_BINARIES = ['google-chrome', 'google-chrome-stable', 'chromium', 'chromium-browser', 'microsoft-edge', 'microsoft-edge-stable', 'brave-browser'];
39
+ const WINDOWS_BINARIES = [
40
+ ['Google\\Chrome\\Application\\chrome.exe', 'Google Chrome'],
41
+ ['Microsoft\\Edge\\Application\\msedge.exe', 'Microsoft Edge'],
42
+ ['Chromium\\Application\\chrome.exe', 'Chromium'],
43
+ ['BraveSoftware\\Brave-Browser\\Application\\brave.exe', 'Brave'],
44
+ ];
45
+ function defaultExists(path) {
46
+ try {
47
+ statSync(path);
48
+ return true;
49
+ }
50
+ catch {
51
+ return false;
52
+ }
53
+ }
54
+ function defaultReadText(path) {
55
+ try {
56
+ return readFileSync(path, 'utf-8');
57
+ }
58
+ catch {
59
+ return undefined;
60
+ }
61
+ }
62
+ /**
63
+ * The executable inside a macOS .app bundle: CFBundleExecutable from
64
+ * Info.plist when it is readable as XML, else the bundle name without ".app".
65
+ */
66
+ export function appBundleExecutable(appPath, readText = defaultReadText) {
67
+ const app = appPath.replace(/\/+$/, '');
68
+ const plist = readText(join(app, 'Contents', 'Info.plist'));
69
+ const declared = plist?.match(/<key>CFBundleExecutable<\/key>\s*<string>([^<]+)<\/string>/)?.[1];
70
+ return join(app, 'Contents', 'MacOS', declared ?? basename(app).replace(/\.app$/i, ''));
71
+ }
72
+ const NOT_FOUND_HINT = 'Set OLCLI_BROWSER to the browser (an .app bundle or the executable), or sign in with the session cookie instead: olcli auth --cookie';
73
+ /**
74
+ * The browser to start. OLCLI_BROWSER first (an executable, or on macOS an
75
+ * .app bundle), then the usual install locations of Chrome, Chromium, Edge
76
+ * and Brave for the platform.
77
+ */
78
+ export function findBrowser(lookup = {}) {
79
+ const env = lookup.env ?? process.env;
80
+ const platform = lookup.platform ?? process.platform;
81
+ const home = lookup.home ?? homedir();
82
+ const exists = lookup.exists ?? defaultExists;
83
+ const readText = lookup.readText ?? defaultReadText;
84
+ const override = env.OLCLI_BROWSER?.trim();
85
+ if (override) {
86
+ const path = /\.app\/?$/i.test(override) ? appBundleExecutable(override, readText) : override;
87
+ if (!exists(path)) {
88
+ throw new BrowserNotFoundError(`OLCLI_BROWSER is set to ${override}, but ${path} does not exist. ${NOT_FOUND_HINT}`);
89
+ }
90
+ return { path, name: basename(path).replace(/\.exe$/i, '') };
91
+ }
92
+ if (platform === 'darwin') {
93
+ for (const dir of ['/Applications', join(home, 'Applications')]) {
94
+ for (const app of MAC_APPS) {
95
+ const bundle = join(dir, `${app}.app`);
96
+ if (!exists(bundle))
97
+ continue;
98
+ const path = appBundleExecutable(bundle, readText);
99
+ if (exists(path))
100
+ return { path, name: app };
101
+ }
102
+ }
103
+ }
104
+ else if (platform === 'win32') {
105
+ const roots = [env.PROGRAMFILES, env['PROGRAMFILES(X86)'], env.LOCALAPPDATA].filter((r) => Boolean(r));
106
+ for (const [relative, name] of WINDOWS_BINARIES) {
107
+ for (const root of roots) {
108
+ const path = `${root.replace(/\\+$/, '')}\\${relative}`;
109
+ if (exists(path))
110
+ return { path, name };
111
+ }
112
+ }
113
+ }
114
+ else {
115
+ const dirs = (env.PATH ?? '').split(delimiter).filter(Boolean);
116
+ for (const binary of LINUX_BINARIES) {
117
+ for (const dir of dirs) {
118
+ const path = join(dir, binary);
119
+ if (exists(path))
120
+ return { path, name: binary };
121
+ }
122
+ }
123
+ }
124
+ throw new BrowserNotFoundError(`No Chrome, Edge, Chromium or Brave found. ${NOT_FOUND_HINT}`);
125
+ }
126
+ function domainMatches(cookieDomain, host) {
127
+ const domain = cookieDomain.replace(/^\./, '').toLowerCase();
128
+ const target = host.replace(/^\[|\]$/g, '').toLowerCase();
129
+ return target === domain || target.endsWith(`.${domain}`);
130
+ }
131
+ /**
132
+ * The session cookie among `cookies`, or undefined. Only a cookie for the
133
+ * instance's host whose name is the configured one or one of the known
134
+ * session cookie names is taken; everything else is ignored, so no other
135
+ * cookie ever leaves this function. The configured name wins over the others.
136
+ */
137
+ export function pickSessionCookie(cookies, baseUrl, preferredName) {
138
+ const host = new URL(baseUrl).hostname;
139
+ const names = [preferredName, ...KNOWN_SESSION_COOKIES.filter((n) => n !== preferredName)];
140
+ for (const name of names) {
141
+ const match = cookies.find((c) => c.name === name && c.value && domainMatches(c.domain, host));
142
+ if (match)
143
+ return { name: match.name, value: match.value };
144
+ }
145
+ return undefined;
146
+ }
147
+ export class BrowserSignInError extends Error {
148
+ constructor(message) {
149
+ super(message);
150
+ this.name = 'BrowserSignInError';
151
+ }
152
+ }
153
+ export class BrowserSignInAborted extends Error {
154
+ constructor() {
155
+ super('Cancelled.');
156
+ this.name = 'BrowserSignInAborted';
157
+ }
158
+ }
159
+ /** Node's WebSocket, or a clear error on Node 20 and 21, which do not ship one. */
160
+ export function requireWebSocket() {
161
+ const ws = globalThis.WebSocket;
162
+ if (!ws) {
163
+ throw new BrowserSignInError(`Browser sign-in needs Node 22 or newer (this is Node ${process.versions.node}). Upgrade Node, or sign in with: olcli auth --cookie`);
164
+ }
165
+ return ws;
166
+ }
167
+ /** A CdpTransport over a WebSocket to the browser endpoint. */
168
+ export async function connectCdp(endpoint) {
169
+ const Ws = requireWebSocket();
170
+ const socket = new Ws(endpoint);
171
+ let nextId = 1;
172
+ const pending = new Map();
173
+ await new Promise((resolve, reject) => {
174
+ socket.addEventListener('open', () => resolve(), { once: true });
175
+ socket.addEventListener('error', () => reject(new BrowserSignInError(`Could not connect to the browser at ${endpoint}.`)), { once: true });
176
+ });
177
+ const failAll = (error) => {
178
+ for (const { reject } of pending.values())
179
+ reject(error);
180
+ pending.clear();
181
+ };
182
+ socket.addEventListener('message', (event) => {
183
+ let message;
184
+ try {
185
+ message = JSON.parse(String(event.data));
186
+ }
187
+ catch {
188
+ return;
189
+ }
190
+ if (typeof message.id !== 'number')
191
+ return;
192
+ const waiter = pending.get(message.id);
193
+ if (!waiter)
194
+ return;
195
+ pending.delete(message.id);
196
+ if (message.error)
197
+ waiter.reject(new BrowserSignInError(`Browser protocol error: ${message.error.message ?? 'unknown'}`));
198
+ else
199
+ waiter.resolve(message.result);
200
+ });
201
+ socket.addEventListener('close', () => failAll(new BrowserSignInError('The browser closed the connection.')));
202
+ return {
203
+ send(method, params = {}, sessionId) {
204
+ if (socket.readyState !== socket.OPEN)
205
+ return Promise.reject(new BrowserSignInError('The browser closed the connection.'));
206
+ const id = nextId++;
207
+ return new Promise((resolve, reject) => {
208
+ pending.set(id, { resolve, reject });
209
+ socket.send(JSON.stringify(sessionId ? { id, method, params, sessionId } : { id, method, params }));
210
+ });
211
+ },
212
+ close() {
213
+ try {
214
+ socket.close();
215
+ }
216
+ catch {
217
+ // Already closed.
218
+ }
219
+ },
220
+ };
221
+ }
222
+ /** Command-line arguments for a throwaway browser session. */
223
+ export function browserArgs(profileDir, url) {
224
+ return [
225
+ `--user-data-dir=${profileDir}`,
226
+ '--remote-debugging-port=0',
227
+ '--remote-debugging-address=127.0.0.1',
228
+ '--no-first-run',
229
+ '--no-default-browser-check',
230
+ '--disable-sync',
231
+ // A throwaway profile needs no OS secret store: without these, macOS may
232
+ // ask for the keychain and Linux for the keyring before the page loads.
233
+ '--use-mock-keychain',
234
+ '--password-store=basic',
235
+ '--new-window',
236
+ url,
237
+ ];
238
+ }
239
+ /**
240
+ * `promise`, but rejected with BrowserSignInAborted when `signal` fires and
241
+ * with a BrowserSignInError after `ms`. A protocol call to a busy or hung
242
+ * browser can stay unanswered; without this, Ctrl-C would wait for it.
243
+ */
244
+ export function guarded(promise, signal, ms, what) {
245
+ return new Promise((resolve, reject) => {
246
+ if (signal.aborted) {
247
+ reject(new BrowserSignInAborted());
248
+ return;
249
+ }
250
+ const onAbort = () => {
251
+ clearTimeout(timer);
252
+ reject(new BrowserSignInAborted());
253
+ };
254
+ const timer = setTimeout(() => {
255
+ signal.removeEventListener('abort', onAbort);
256
+ reject(new BrowserSignInError(`The browser did not answer (${what}) within ${Math.round(ms / 1000)} seconds.`));
257
+ }, ms);
258
+ signal.addEventListener('abort', onAbort, { once: true });
259
+ promise.then((value) => { clearTimeout(timer); signal.removeEventListener('abort', onAbort); resolve(value); }, (error) => { clearTimeout(timer); signal.removeEventListener('abort', onAbort); reject(error); });
260
+ });
261
+ }
262
+ async function sleep(ms, signal) {
263
+ await new Promise((resolve) => {
264
+ const timer = setTimeout(resolve, ms);
265
+ signal?.addEventListener('abort', () => {
266
+ clearTimeout(timer);
267
+ resolve();
268
+ }, { once: true });
269
+ });
270
+ }
271
+ /**
272
+ * The real StartBrowser: spawn `executable`, wait for it to write
273
+ * DevToolsActivePort into the profile, then connect to the browser endpoint.
274
+ * `--remote-debugging-port=0` lets the browser pick a free port.
275
+ */
276
+ export function chromiumLauncher(executable) {
277
+ return async (profileDir, url, signal) => {
278
+ requireWebSocket();
279
+ const child = spawn(executable, browserArgs(profileDir, url), { stdio: 'ignore', detached: false });
280
+ let exitedFlag = false;
281
+ const exited = new Promise((resolve) => {
282
+ child.once('exit', () => { exitedFlag = true; resolve(); });
283
+ child.once('error', () => { exitedFlag = true; resolve(); });
284
+ });
285
+ const kill = async () => {
286
+ if (exitedFlag)
287
+ return;
288
+ child.kill('SIGTERM');
289
+ await Promise.race([exited, sleep(3000)]);
290
+ if (!exitedFlag) {
291
+ child.kill('SIGKILL');
292
+ await Promise.race([exited, sleep(2000)]);
293
+ }
294
+ };
295
+ try {
296
+ const portFile = join(profileDir, 'DevToolsActivePort');
297
+ const deadline = Date.now() + 30_000;
298
+ let endpoint;
299
+ while (!endpoint) {
300
+ if (signal.aborted)
301
+ throw new BrowserSignInAborted();
302
+ if (exitedFlag)
303
+ throw new BrowserSignInError(`The browser (${executable}) exited before it was ready.`);
304
+ if (Date.now() > deadline)
305
+ throw new BrowserSignInError('The browser did not open its DevTools port within 30 seconds.');
306
+ const content = existsSync(portFile) ? readFileSync(portFile, 'utf-8').split('\n') : [];
307
+ if (content.length >= 2 && /^\d+$/.test(content[0].trim()) && content[1].trim().startsWith('/')) {
308
+ endpoint = `ws://127.0.0.1:${content[0].trim()}${content[1].trim()}`;
309
+ }
310
+ else {
311
+ await sleep(100, signal);
312
+ }
313
+ }
314
+ const cdp = await connectCdp(endpoint);
315
+ return {
316
+ cdp,
317
+ exited,
318
+ async stop() {
319
+ if (!exitedFlag) {
320
+ await Promise.race([cdp.send('Browser.close').catch(() => undefined), sleep(2000)]);
321
+ await Promise.race([exited, sleep(3000)]);
322
+ }
323
+ cdp.close();
324
+ await kill();
325
+ },
326
+ };
327
+ }
328
+ catch (error) {
329
+ await kill();
330
+ throw error;
331
+ }
332
+ };
333
+ }
334
+ /**
335
+ * An unchanged cookie is validated against the instance at most this often.
336
+ * A new cookie value is validated at once, so a login that replaces the
337
+ * session id is picked up within a second; one that keeps it within 7 s.
338
+ * Over the 5-minute wait that is at most about 43 project-list requests.
339
+ */
340
+ export const BROWSER_SIGN_IN_RECHECK_MS = 7000;
341
+ /**
342
+ * Open `<baseUrl>/login` in a throwaway browser profile and wait until the
343
+ * profile holds a session cookie that `validate` accepts. Returns that cookie
344
+ * only. The browser is closed and the profile deleted on every way out.
345
+ */
346
+ export async function browserSignIn(options) {
347
+ const timeoutMs = options.timeoutMs ?? BROWSER_SIGN_IN_TIMEOUT_MS;
348
+ const pollMs = options.pollMs ?? 1000;
349
+ const recheckMs = options.recheckMs ?? BROWSER_SIGN_IN_RECHECK_MS;
350
+ const base = options.baseUrl.replace(/\/+$/, '');
351
+ const profileDir = mkdtempSync(join(options.tmpRoot ?? tmpdir(), 'olcli-browser-'));
352
+ options.onProfile?.(profileDir);
353
+ const local = new AbortController();
354
+ const signal = options.signal ? AbortSignal.any([options.signal, local.signal]) : local.signal;
355
+ let browser;
356
+ let closedByUser = false;
357
+ try {
358
+ if (signal.aborted)
359
+ throw new BrowserSignInAborted();
360
+ browser = await options.startBrowser(profileDir, `${base}/login`, signal);
361
+ browser.exited.then(() => { closedByUser = true; local.abort(); });
362
+ // Network.getCookies with a URL filter returns only the cookies the
363
+ // browser would send to the instance, so olcli never receives the cookies
364
+ // of an SSO provider. It needs a page session, hence the attach.
365
+ const cdp = browser.cdp;
366
+ const call = (method, params, session) => guarded(cdp.send(method, params, session), signal, 15_000, method);
367
+ const attach = async () => {
368
+ const { targetInfos } = await call('Target.getTargets');
369
+ const page = targetInfos.find((t) => t.type === 'page');
370
+ if (!page)
371
+ return undefined;
372
+ const { sessionId } = await call('Target.attachToTarget', { targetId: page.targetId, flatten: true });
373
+ return sessionId;
374
+ };
375
+ let sessionId = await attach();
376
+ if (!sessionId)
377
+ throw new BrowserSignInError('The browser opened no page to sign in on.');
378
+ const deadline = Date.now() + timeoutMs;
379
+ let lastTried;
380
+ let lastTriedAt = 0;
381
+ while (Date.now() < deadline) {
382
+ if (signal.aborted)
383
+ break;
384
+ let cookies = [];
385
+ try {
386
+ const result = await call('Network.getCookies', { urls: [`${base}/`] }, sessionId);
387
+ cookies = (result?.cookies ?? []);
388
+ }
389
+ catch {
390
+ if (signal.aborted)
391
+ break;
392
+ // The tab olcli attached to was closed: move to another one, and
393
+ // give up only when the user closed every window.
394
+ sessionId = await attach().catch(() => undefined);
395
+ if (signal.aborted)
396
+ break;
397
+ if (!sessionId) {
398
+ throw new BrowserSignInError('The browser window was closed before the sign-in finished. Run olcli auth --browser again.');
399
+ }
400
+ continue;
401
+ }
402
+ const candidate = pickSessionCookie(cookies, base, options.cookieName);
403
+ // Re-check the same value now and then: Overleaf may keep the session
404
+ // id across the login and only mark the session as logged in.
405
+ if (candidate && (candidate.value !== lastTried || Date.now() - lastTriedAt >= recheckMs)) {
406
+ lastTried = candidate.value;
407
+ lastTriedAt = Date.now();
408
+ let valid = false;
409
+ try {
410
+ valid = await guarded(options.validate(candidate), signal, 60_000, 'validation');
411
+ }
412
+ catch {
413
+ valid = false;
414
+ }
415
+ if (valid)
416
+ return candidate;
417
+ }
418
+ await sleep(pollMs, signal);
419
+ }
420
+ if (closedByUser && !options.signal?.aborted) {
421
+ throw new BrowserSignInError('The browser was closed before the sign-in finished. Run olcli auth --browser again.');
422
+ }
423
+ if (signal.aborted)
424
+ throw new BrowserSignInAborted();
425
+ throw new BrowserSignInError(`No sign-in within ${Math.round(timeoutMs / 1000)} seconds. Run olcli auth --browser again, or use olcli auth --cookie.`);
426
+ }
427
+ finally {
428
+ if (browser)
429
+ await browser.stop().catch(() => undefined);
430
+ removeProfile(profileDir);
431
+ }
432
+ }
433
+ /** Delete a temporary profile. Retries, since the browser may still be writing. */
434
+ export function removeProfile(profileDir) {
435
+ try {
436
+ rmSync(profileDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 200 });
437
+ }
438
+ catch {
439
+ // Last resort; the OS cleans its temp directory eventually.
440
+ }
441
+ }
442
+ //# sourceMappingURL=browser-auth.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"browser-auth.js","sourceRoot":"","sources":["../src/browser-auth.ts"],"names":[],"mappings":"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"}