browser-commander 0.21.2 → 0.23.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/.jscpd-baseline.json +5 -6
- package/CHANGELOG.md +43 -0
- package/package.json +1 -1
- package/src/browser/browser-cookie-credentials.js +15 -24
- package/src/browser/browser-cookies.js +251 -11
- package/src/browser/browser-profiles.js +163 -79
- package/src/browser/browser-sources.js +184 -0
- package/src/browser/browser-sources.json +429 -0
- package/src/browser/default-browser.js +176 -0
- package/src/browser/migration/cookies.js +3 -0
- package/src/browser/migration/index.js +74 -14
- package/src/browser/safari-cookies.js +173 -0
- package/src/cli/args.js +10 -0
- package/src/cli/commands.js +27 -0
- package/src/cli/high-level-methods.js +28 -2
- package/src/cli/modules.js +6 -0
- package/src/exports.js +4 -0
- package/tests/helpers/cli-fakes.js +21 -0
- package/tests/helpers/migration-fixtures.js +30 -1
- package/tests/unit/browser/browser-cookies-profiledir.test.js +36 -0
- package/tests/unit/browser/browser-cookies.test.js +2 -11
- package/tests/unit/browser/browser-profiles-sources.test.js +150 -0
- package/tests/unit/browser/browser-sources.test.js +154 -0
- package/tests/unit/browser/cookie-sources.test.js +146 -0
- package/tests/unit/browser/default-browser.test.js +121 -0
- package/tests/unit/browser/migration/index.test.js +62 -1
- package/tests/unit/browser/safari-cookies.test.js +246 -0
- package/tests/unit/cli/main.test.js +32 -5
- package/tests/unit/scripts/browser-support.test.js +56 -0
package/.jscpd-baseline.json
CHANGED
|
@@ -19,6 +19,7 @@
|
|
|
19
19
|
"0fd23be8410c2c95": 1,
|
|
20
20
|
"0fe4f3b5e5e939b3": 1,
|
|
21
21
|
"1019ebbe7f07a5ad": 1,
|
|
22
|
+
"119f429fe4d23e4a": 1,
|
|
22
23
|
"1273365073edd790": 1,
|
|
23
24
|
"1296adc3c3128048": 1,
|
|
24
25
|
"13c4b58d3ea0719b": 1,
|
|
@@ -54,11 +55,11 @@
|
|
|
54
55
|
"2e70be24d2268673": 1,
|
|
55
56
|
"2f4c9810eae87d6f": 1,
|
|
56
57
|
"2f9e15467cc2f12a": 1,
|
|
58
|
+
"30da9d4e83f1c939": 1,
|
|
57
59
|
"3101802d3ea65339": 1,
|
|
58
60
|
"33357ce94e07cc4b": 1,
|
|
59
61
|
"35cf2769645f3234": 1,
|
|
60
62
|
"37bd4114d0089f49": 1,
|
|
61
|
-
"389df6fb4b8315a1": 1,
|
|
62
63
|
"39eaada6d1879f4a": 1,
|
|
63
64
|
"3a9f1672ecc1d55b": 1,
|
|
64
65
|
"3adca52a3f04837c": 1,
|
|
@@ -77,6 +78,7 @@
|
|
|
77
78
|
"4c3b94caa28045d0": 1,
|
|
78
79
|
"4e090d6bb30e6551": 1,
|
|
79
80
|
"4f3c541b3f3e3f23": 1,
|
|
81
|
+
"4f93b074bc2ac9e8": 1,
|
|
80
82
|
"5085765e1f103f3e": 1,
|
|
81
83
|
"5184c90c9f8406c3": 1,
|
|
82
84
|
"520a28ee2ced56c2": 1,
|
|
@@ -153,11 +155,9 @@
|
|
|
153
155
|
"92ddafa7e65be7eb": 1,
|
|
154
156
|
"94821a4d1b745dfd": 1,
|
|
155
157
|
"97c5a112fdde7be8": 1,
|
|
156
|
-
"98cc22079feaa004": 1,
|
|
157
158
|
"990d87f21678fa96": 1,
|
|
158
159
|
"9a72b1c2f22156ca": 1,
|
|
159
160
|
"9b6ef4df04562546": 1,
|
|
160
|
-
"9c055dfd90c369bf": 1,
|
|
161
161
|
"9ee57dcd5e7a6691": 1,
|
|
162
162
|
"9fbb8296259dedbe": 1,
|
|
163
163
|
"a0183465782b0b15": 1,
|
|
@@ -167,11 +167,11 @@
|
|
|
167
167
|
"a305c6cac16f3af5": 1,
|
|
168
168
|
"a4c8498d4f2d2191": 1,
|
|
169
169
|
"a6ad7ab6c05656dc": 1,
|
|
170
|
+
"a6ffab1aacd00af6": 1,
|
|
170
171
|
"a78d76908162699e": 1,
|
|
171
172
|
"a9bd4ffef6da5faf": 1,
|
|
172
173
|
"a9d71c2e50f1b832": 1,
|
|
173
174
|
"acc95d694eb2f581": 1,
|
|
174
|
-
"ad4469f2e8131535": 1,
|
|
175
175
|
"ad4cfa76daa1b6fc": 1,
|
|
176
176
|
"ad50b48938af8aef": 1,
|
|
177
177
|
"adae1329361a81a1": 1,
|
|
@@ -190,7 +190,6 @@
|
|
|
190
190
|
"bb269582b94ed42d": 1,
|
|
191
191
|
"bb3e6d0f7e7edccd": 1,
|
|
192
192
|
"bc9115be3a462930": 1,
|
|
193
|
-
"bccf0d5cc57c08df": 1,
|
|
194
193
|
"bd0ae42c13d5b4f9": 1,
|
|
195
194
|
"bd6c62a6e1c6a071": 1,
|
|
196
195
|
"bdb8ca169be36b80": 1,
|
|
@@ -207,10 +206,10 @@
|
|
|
207
206
|
"c9cf3c28bed33a5b": 1,
|
|
208
207
|
"cab590a1d04b5a05": 1,
|
|
209
208
|
"cbd444e9a6a9072e": 1,
|
|
210
|
-
"cd49f39b43d14635": 1,
|
|
211
209
|
"cebff7d1cc87f646": 1,
|
|
212
210
|
"cf6116d195199f8a": 1,
|
|
213
211
|
"cfd68135b744c27b": 1,
|
|
212
|
+
"d016035b3bf3340c": 1,
|
|
214
213
|
"d097f41a6f43e634": 1,
|
|
215
214
|
"d0da8714c4b7de30": 1,
|
|
216
215
|
"d17201496391f6cc": 1,
|
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,48 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.23.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- b56775b: Add Safari and Safari Technology Preview cookie sources, including installed,
|
|
8
|
+
default/auto and custom-directory import, counts-only domain discovery, validated
|
|
9
|
+
binarycookies decoding and actionable Full Disk Access errors. Migration reports
|
|
10
|
+
unsupported Safari classes and the SameSite Lax fallback. Other Safari stores,
|
|
11
|
+
Firefox/WebKit targets, full clones and additional data classes remain tracked in
|
|
12
|
+
issues #117–#120; this release does not claim full Safari profile import.
|
|
13
|
+
|
|
14
|
+
## 0.22.0
|
|
15
|
+
|
|
16
|
+
### Minor Changes
|
|
17
|
+
|
|
18
|
+
- f4ce84c: Add a shared catalogue of importable browsers and resolve the system default
|
|
19
|
+
(#114).
|
|
20
|
+
|
|
21
|
+
- `browser-sources.json` is a shared, data-driven catalogue of the browsers
|
|
22
|
+
Browser Commander can import from — Chrome and its Beta/Dev/Canary channels,
|
|
23
|
+
Edge channels, Brave variants, Chromium, Opera and Opera GX, Vivaldi, Arc,
|
|
24
|
+
Yandex, and Firefox with its LibreWolf, Waterfox, Zen, Floorp, Developer
|
|
25
|
+
Edition and Nightly forks. It records each browser's per-platform profile
|
|
26
|
+
roots, Chromium Safe Storage identity, and operating-system default
|
|
27
|
+
identifiers, and ships byte-identical to the Python and Rust packages.
|
|
28
|
+
- `browser: 'default'` (or `'auto'`) now resolves the operating-system default
|
|
29
|
+
web browser (macOS LaunchServices, Linux `xdg-settings`/`xdg-mime`, Windows
|
|
30
|
+
`UserChoice` ProgId) to a catalogue id, so an import follows whichever
|
|
31
|
+
browser a person actually uses.
|
|
32
|
+
- Profile discovery and migration classify a browser's engine family from the
|
|
33
|
+
catalogue instead of a hard-coded list, so every catalogued Chromium variant
|
|
34
|
+
and Firefox fork is recognised, and reading cookies honours a custom
|
|
35
|
+
`userDataDir`.
|
|
36
|
+
- New `cookies sources` and `profile sources` commands (and the
|
|
37
|
+
`cookies.sources`/`profile.sources` JSON-RPC methods) report which browsers
|
|
38
|
+
and profiles hold cookies — optionally for specific `--domain`s — as names
|
|
39
|
+
and counts only, never values.
|
|
40
|
+
- A `default`/`auto` migration scoped to `domains` falls back from a default
|
|
41
|
+
browser that holds no cookies for them to the installed profile holding the
|
|
42
|
+
most, and reports which one with a `default-browser-fallback` warning
|
|
43
|
+
(`resolveImportSource`). Migrating from Opera or Opera GX now reads their
|
|
44
|
+
single profile from the user data directory itself.
|
|
45
|
+
|
|
3
46
|
## 0.21.2
|
|
4
47
|
|
|
5
48
|
### Patch Changes
|
package/package.json
CHANGED
|
@@ -1,29 +1,20 @@
|
|
|
1
1
|
import { readFile } from 'node:fs/promises';
|
|
2
2
|
|
|
3
3
|
import { runCommand as runSubprocess } from '../utilities/subprocess.js';
|
|
4
|
+
import { safeStorageIdentity } from './browser-sources.js';
|
|
4
5
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
application: 'chromium',
|
|
18
|
-
folder: 'Chromium Keys',
|
|
19
|
-
service: 'Chromium Safe Storage',
|
|
20
|
-
},
|
|
21
|
-
edge: {
|
|
22
|
-
application: 'microsoft-edge',
|
|
23
|
-
folder: 'Microsoft Edge Keys',
|
|
24
|
-
service: 'Microsoft Edge Safe Storage',
|
|
25
|
-
},
|
|
26
|
-
};
|
|
6
|
+
/**
|
|
7
|
+
* The Chromium Safe Storage identity for a browser, from the shared
|
|
8
|
+
* `browser-sources.json` catalogue. Firefox-family browsers return
|
|
9
|
+
* `undefined` because they do not use OSCrypt.
|
|
10
|
+
*/
|
|
11
|
+
function safeStorageFor(browser) {
|
|
12
|
+
try {
|
|
13
|
+
return safeStorageIdentity(browser);
|
|
14
|
+
} catch {
|
|
15
|
+
return undefined;
|
|
16
|
+
}
|
|
17
|
+
}
|
|
27
18
|
|
|
28
19
|
/**
|
|
29
20
|
* Run a credential tool (`security`, `secret-tool`, `kwallet-query`,
|
|
@@ -35,7 +26,7 @@ async function runCredentialCommand(command, args, environment) {
|
|
|
35
26
|
}
|
|
36
27
|
|
|
37
28
|
async function readLinuxSafeStoragePassword(browser, environment, runCommand) {
|
|
38
|
-
const identity =
|
|
29
|
+
const identity = safeStorageFor(browser);
|
|
39
30
|
try {
|
|
40
31
|
const password = await runCommand(
|
|
41
32
|
'secret-tool',
|
|
@@ -72,7 +63,7 @@ export async function readSafeStoragePassword({
|
|
|
72
63
|
environment = process.env,
|
|
73
64
|
runCredentialCommand: runCommand = runCredentialCommand,
|
|
74
65
|
}) {
|
|
75
|
-
const identity =
|
|
66
|
+
const identity = safeStorageFor(browser);
|
|
76
67
|
if (!identity) {
|
|
77
68
|
throw new Error(`No Safe Storage identity is known for ${browser}`);
|
|
78
69
|
}
|
|
@@ -24,12 +24,20 @@ import {
|
|
|
24
24
|
openSqliteDatabase,
|
|
25
25
|
preserveIntegerPrecision,
|
|
26
26
|
} from './browser-cookie-database.js';
|
|
27
|
+
import { browserFamily } from './browser-sources.js';
|
|
27
28
|
import {
|
|
28
29
|
findCookieDatabase,
|
|
30
|
+
isDefaultBrowserKeyword,
|
|
29
31
|
listBrowserProfiles,
|
|
30
|
-
normalizeCookieBrowser,
|
|
31
32
|
resolveBrowserProfile,
|
|
33
|
+
resolveSourceBrowser,
|
|
32
34
|
} from './browser-profiles.js';
|
|
35
|
+
import { resolveDefaultBrowser } from './default-browser.js';
|
|
36
|
+
import {
|
|
37
|
+
countSafariCookies,
|
|
38
|
+
parseSafariCookies,
|
|
39
|
+
readSafariCookieFile,
|
|
40
|
+
} from './safari-cookies.js';
|
|
33
41
|
|
|
34
42
|
const CHROME_EPOCH_OFFSET_SECONDS = 11_644_473_600n;
|
|
35
43
|
const MICROSECONDS_PER_SECOND = 1_000_000n;
|
|
@@ -266,20 +274,33 @@ export async function readBrowserCookiesWithDependencies(
|
|
|
266
274
|
if (!options || typeof options !== 'object') {
|
|
267
275
|
throw new TypeError('readBrowserCookies requires an options object');
|
|
268
276
|
}
|
|
269
|
-
const browser = normalizeCookieBrowser(options.browser);
|
|
270
277
|
const platform = dependencies.platform ?? process.platform;
|
|
271
278
|
const homeDir = dependencies.homeDir ?? os.homedir();
|
|
272
279
|
const environment = dependencies.environment ?? process.env;
|
|
273
|
-
const
|
|
274
|
-
|
|
275
|
-
profile: options.profile,
|
|
280
|
+
const runCommand = dependencies.runCommand;
|
|
281
|
+
const browser = await resolveSourceBrowser(options.browser, {
|
|
276
282
|
platform,
|
|
277
|
-
homeDir,
|
|
278
283
|
environment,
|
|
284
|
+
runCommand,
|
|
279
285
|
});
|
|
280
|
-
|
|
286
|
+
// A caller that already resolved the profile directory (for example a
|
|
287
|
+
// migration honouring a custom `userDataDir`) passes it as `profileDir`, so
|
|
288
|
+
// the reader does not re-resolve the default profile location.
|
|
289
|
+
const profilePath = options.profileDir
|
|
290
|
+
? options.profileDir
|
|
291
|
+
: (
|
|
292
|
+
await resolveBrowserProfile({
|
|
293
|
+
browser,
|
|
294
|
+
profile: options.profile,
|
|
295
|
+
platform,
|
|
296
|
+
homeDir,
|
|
297
|
+
environment,
|
|
298
|
+
runCommand,
|
|
299
|
+
})
|
|
300
|
+
).path;
|
|
301
|
+
const cookiePath = await findCookieDatabase(browser, profilePath, platform);
|
|
281
302
|
if (!cookiePath) {
|
|
282
|
-
throw new Error(`No cookie database exists in ${
|
|
303
|
+
throw new Error(`No cookie database exists in ${profilePath}`);
|
|
283
304
|
}
|
|
284
305
|
const cache = normalizeCookieCache(
|
|
285
306
|
options.cache,
|
|
@@ -288,7 +309,7 @@ export async function readBrowserCookiesWithDependencies(
|
|
|
288
309
|
);
|
|
289
310
|
const identity = JSON.stringify({
|
|
290
311
|
browser,
|
|
291
|
-
profile:
|
|
312
|
+
profile: profilePath,
|
|
292
313
|
domainFilter: options.domainFilter ?? null,
|
|
293
314
|
ignoreDecryptionErrors: options.ignoreDecryptionErrors === true,
|
|
294
315
|
});
|
|
@@ -303,10 +324,18 @@ export async function readBrowserCookiesWithDependencies(
|
|
|
303
324
|
return cachedCookies;
|
|
304
325
|
}
|
|
305
326
|
|
|
327
|
+
if (browserFamily(browser) === 'safari') {
|
|
328
|
+
const cookies = parseSafariCookies(
|
|
329
|
+
await readSafariCookieFile(cookiePath, { environment }),
|
|
330
|
+
options.domainFilter
|
|
331
|
+
);
|
|
332
|
+
await writeCookieResultCache({ cache, identity, cookies, now });
|
|
333
|
+
return cookies;
|
|
334
|
+
}
|
|
306
335
|
const database = await openCookieDatabase(cookiePath);
|
|
307
336
|
let cookies;
|
|
308
337
|
try {
|
|
309
|
-
if (browser === 'firefox') {
|
|
338
|
+
if (browserFamily(browser) === 'firefox') {
|
|
310
339
|
cookies = mapFirefoxCookieRows(
|
|
311
340
|
readFirefoxRows(database, options.domainFilter)
|
|
312
341
|
);
|
|
@@ -323,7 +352,7 @@ export async function readBrowserCookiesWithDependencies(
|
|
|
323
352
|
ignoreDecryptionErrors: options.ignoreDecryptionErrors === true,
|
|
324
353
|
now,
|
|
325
354
|
platform,
|
|
326
|
-
profile,
|
|
355
|
+
profile: { path: profilePath },
|
|
327
356
|
readSafeStoragePassword:
|
|
328
357
|
dependencies.readSafeStoragePassword ?? readSafeStoragePassword,
|
|
329
358
|
readWindowsEncryptionKey:
|
|
@@ -343,6 +372,217 @@ export function readBrowserCookies(options) {
|
|
|
343
372
|
return readBrowserCookiesWithDependencies(options);
|
|
344
373
|
}
|
|
345
374
|
|
|
375
|
+
/**
|
|
376
|
+
* Count cookies in a database by domain, without ever reading a cookie value.
|
|
377
|
+
* Only host names and row counts are touched, so this is safe to expose for a
|
|
378
|
+
* "which browser holds cookies for this domain" listing.
|
|
379
|
+
*/
|
|
380
|
+
function countCookiesByDomain(database, family, domains) {
|
|
381
|
+
const column = family === 'firefox' ? 'host' : 'host_key';
|
|
382
|
+
const table = family === 'firefox' ? 'moz_cookies' : 'cookies';
|
|
383
|
+
const countFor = (filter) => {
|
|
384
|
+
const query = filter
|
|
385
|
+
? `SELECT COUNT(*) AS n FROM ${table} WHERE ${column} LIKE ?`
|
|
386
|
+
: `SELECT COUNT(*) AS n FROM ${table}`;
|
|
387
|
+
const statement = database.prepare(query);
|
|
388
|
+
const row = filter ? statement.get(`%${filter}%`) : statement.get();
|
|
389
|
+
return Number(row?.n ?? 0);
|
|
390
|
+
};
|
|
391
|
+
const total = countFor(null);
|
|
392
|
+
if (!Array.isArray(domains) || domains.length === 0) {
|
|
393
|
+
return { total, byDomain: null };
|
|
394
|
+
}
|
|
395
|
+
const byDomain = {};
|
|
396
|
+
for (const domain of domains) {
|
|
397
|
+
byDomain[domain] = countFor(domain);
|
|
398
|
+
}
|
|
399
|
+
return { total, byDomain };
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
/**
|
|
403
|
+
* List the installed browser profiles that hold cookies, with per-domain
|
|
404
|
+
* counts when `domains` is given. Values are never read or returned — this is
|
|
405
|
+
* the data behind the `cookies sources` command.
|
|
406
|
+
*
|
|
407
|
+
* @param {Object} [options]
|
|
408
|
+
* @param {string[]} [options.domains] - Restrict and count by these domains
|
|
409
|
+
* @param {string} [options.platform=process.platform]
|
|
410
|
+
* @param {string} [options.homeDir=os.homedir()]
|
|
411
|
+
* @param {Object} [options.environment=process.env]
|
|
412
|
+
* @returns {Promise<Array<Object>>} One entry per profile:
|
|
413
|
+
* `{browser, profile, path, isDefault, cookies, byDomain}`, plus `error`
|
|
414
|
+
* when the database could not be read
|
|
415
|
+
*/
|
|
416
|
+
export async function listCookieSources({
|
|
417
|
+
domains,
|
|
418
|
+
platform = process.platform,
|
|
419
|
+
homeDir = os.homedir(),
|
|
420
|
+
environment = process.env,
|
|
421
|
+
} = {}) {
|
|
422
|
+
const profiles = await listBrowserProfiles({
|
|
423
|
+
platform,
|
|
424
|
+
homeDir,
|
|
425
|
+
environment,
|
|
426
|
+
});
|
|
427
|
+
const sources = [];
|
|
428
|
+
for (const profile of profiles) {
|
|
429
|
+
const cookiePath = await findCookieDatabase(
|
|
430
|
+
profile.browser,
|
|
431
|
+
profile.path,
|
|
432
|
+
platform
|
|
433
|
+
);
|
|
434
|
+
if (!cookiePath) {
|
|
435
|
+
continue;
|
|
436
|
+
}
|
|
437
|
+
const family = browserFamily(profile.browser);
|
|
438
|
+
let counts;
|
|
439
|
+
let error;
|
|
440
|
+
let database;
|
|
441
|
+
try {
|
|
442
|
+
if (family === 'safari') {
|
|
443
|
+
counts = countSafariCookies(
|
|
444
|
+
await readSafariCookieFile(cookiePath, { environment }),
|
|
445
|
+
domains
|
|
446
|
+
);
|
|
447
|
+
} else {
|
|
448
|
+
database = await openCookieDatabase(cookiePath);
|
|
449
|
+
counts = countCookiesByDomain(database, family, domains);
|
|
450
|
+
}
|
|
451
|
+
} catch (openError) {
|
|
452
|
+
error = openError.message;
|
|
453
|
+
} finally {
|
|
454
|
+
database?.close();
|
|
455
|
+
}
|
|
456
|
+
if (error) {
|
|
457
|
+
sources.push({
|
|
458
|
+
browser: profile.browser,
|
|
459
|
+
profile: profile.name,
|
|
460
|
+
path: profile.path,
|
|
461
|
+
isDefault: profile.isDefault,
|
|
462
|
+
error,
|
|
463
|
+
});
|
|
464
|
+
continue;
|
|
465
|
+
}
|
|
466
|
+
// When filtering by domain, skip profiles that hold none of them.
|
|
467
|
+
const matchedCount = counts.byDomain
|
|
468
|
+
? Object.values(counts.byDomain).reduce((sum, n) => sum + n, 0)
|
|
469
|
+
: counts.total;
|
|
470
|
+
if (Array.isArray(domains) && domains.length > 0 && matchedCount === 0) {
|
|
471
|
+
continue;
|
|
472
|
+
}
|
|
473
|
+
sources.push({
|
|
474
|
+
browser: profile.browser,
|
|
475
|
+
profile: profile.name,
|
|
476
|
+
path: profile.path,
|
|
477
|
+
isDefault: profile.isDefault,
|
|
478
|
+
cookies: counts.total,
|
|
479
|
+
byDomain: counts.byDomain,
|
|
480
|
+
});
|
|
481
|
+
}
|
|
482
|
+
return sources;
|
|
483
|
+
}
|
|
484
|
+
|
|
485
|
+
function matchedCookies(source) {
|
|
486
|
+
return Object.values(source.byDomain ?? {}).reduce((sum, n) => sum + n, 0);
|
|
487
|
+
}
|
|
488
|
+
|
|
489
|
+
/**
|
|
490
|
+
* Pick the source browser for an import. A `default`/`auto` request scoped to
|
|
491
|
+
* `domains` uses the system default browser when it holds cookies for them
|
|
492
|
+
* and otherwise falls back to the installed browser profile holding the most,
|
|
493
|
+
* so "import my github.com sign-in" works whichever browser has it. Only
|
|
494
|
+
* names and counts are read (see `listCookieSources`), never cookie values.
|
|
495
|
+
*
|
|
496
|
+
* @param {Object} options
|
|
497
|
+
* @param {string} options.browser - Catalogue id, `default` or `auto`
|
|
498
|
+
* @param {string[]} [options.domains]
|
|
499
|
+
* @param {string} [options.platform=process.platform]
|
|
500
|
+
* @param {string} [options.homeDir=os.homedir()]
|
|
501
|
+
* @param {Object} [options.environment=process.env]
|
|
502
|
+
* @param {Function} [options.runCommand] - Injected for default-browser lookup
|
|
503
|
+
* @returns {Promise<Object>} `{browser, profile, warning}`: `profile` is the
|
|
504
|
+
* profile holding the cookies (when one was chosen) and `warning` is a
|
|
505
|
+
* migration-report warning explaining a fallback away from the system
|
|
506
|
+
* default (reason `default-browser-fallback` or `default-browser-unknown`),
|
|
507
|
+
* or `null`
|
|
508
|
+
*/
|
|
509
|
+
export async function resolveImportSource({
|
|
510
|
+
browser,
|
|
511
|
+
domains,
|
|
512
|
+
platform = process.platform,
|
|
513
|
+
homeDir = os.homedir(),
|
|
514
|
+
environment = process.env,
|
|
515
|
+
runCommand,
|
|
516
|
+
}) {
|
|
517
|
+
if (
|
|
518
|
+
!isDefaultBrowserKeyword(browser) ||
|
|
519
|
+
!Array.isArray(domains) ||
|
|
520
|
+
domains.length === 0
|
|
521
|
+
) {
|
|
522
|
+
return {
|
|
523
|
+
browser: await resolveSourceBrowser(browser, {
|
|
524
|
+
platform,
|
|
525
|
+
environment,
|
|
526
|
+
runCommand,
|
|
527
|
+
}),
|
|
528
|
+
profile: undefined,
|
|
529
|
+
warning: null,
|
|
530
|
+
};
|
|
531
|
+
}
|
|
532
|
+
const systemDefault = await resolveDefaultBrowser({
|
|
533
|
+
platform,
|
|
534
|
+
environment,
|
|
535
|
+
runCommand,
|
|
536
|
+
});
|
|
537
|
+
const listedSources = await listCookieSources({
|
|
538
|
+
domains,
|
|
539
|
+
platform,
|
|
540
|
+
homeDir,
|
|
541
|
+
environment,
|
|
542
|
+
});
|
|
543
|
+
const holders = listedSources.filter((source) => !source.error);
|
|
544
|
+
const fromDefault = holders.filter(
|
|
545
|
+
(source) => source.browser === systemDefault
|
|
546
|
+
);
|
|
547
|
+
const unreadableDefault = listedSources.find(
|
|
548
|
+
(source) => source.browser === systemDefault && source.error
|
|
549
|
+
);
|
|
550
|
+
if (fromDefault.length === 0 && unreadableDefault) {
|
|
551
|
+
throw new Error(
|
|
552
|
+
`Could not inspect the default browser (${systemDefault}): ${unreadableDefault.error}`
|
|
553
|
+
);
|
|
554
|
+
}
|
|
555
|
+
const candidates = fromDefault.length > 0 ? fromDefault : holders;
|
|
556
|
+
if (candidates.length === 0) {
|
|
557
|
+
if (!systemDefault) {
|
|
558
|
+
throw new Error(
|
|
559
|
+
`Could not determine the system default browser, and no installed browser holds cookies for ${domains.join(', ')}.`
|
|
560
|
+
);
|
|
561
|
+
}
|
|
562
|
+
return { browser: systemDefault, profile: undefined, warning: null };
|
|
563
|
+
}
|
|
564
|
+
// The first profile with the most matching cookies; listing order breaks
|
|
565
|
+
// ties, so a browser's default profile wins over its others.
|
|
566
|
+
const best = candidates.reduce((chosen, source) =>
|
|
567
|
+
matchedCookies(source) > matchedCookies(chosen) ? source : chosen
|
|
568
|
+
);
|
|
569
|
+
let warning = null;
|
|
570
|
+
if (best.browser !== systemDefault) {
|
|
571
|
+
const reason = systemDefault
|
|
572
|
+
? `The default browser (${systemDefault}) holds no cookies for`
|
|
573
|
+
: 'Could not determine the default browser to read cookies for';
|
|
574
|
+
warning = {
|
|
575
|
+
type: 'source',
|
|
576
|
+
item: best.browser,
|
|
577
|
+
reason: systemDefault
|
|
578
|
+
? 'default-browser-fallback'
|
|
579
|
+
: 'default-browser-unknown',
|
|
580
|
+
detail: `${reason} ${domains.join(', ')}; imported from ${best.browser} instead.`,
|
|
581
|
+
};
|
|
582
|
+
}
|
|
583
|
+
return { browser: best.browser, profile: best.profile, warning };
|
|
584
|
+
}
|
|
585
|
+
|
|
346
586
|
export {
|
|
347
587
|
clearBrowserCookieMemoryCache,
|
|
348
588
|
decryptChromiumCookie,
|