sqlite-cookie-parser 1.0.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/README.md +164 -0
- package/dist/bravoLinuxCookie.d.ts +5 -0
- package/dist/bravoLinuxCookie.js +12 -0
- package/dist/bravoLinuxCookie.js.map +1 -0
- package/dist/bravoMacCookie.d.ts +5 -0
- package/dist/bravoMacCookie.js +12 -0
- package/dist/bravoMacCookie.js.map +1 -0
- package/dist/bravoWindowsCookie.d.ts +5 -0
- package/dist/bravoWindowsCookie.js +12 -0
- package/dist/bravoWindowsCookie.js.map +1 -0
- package/dist/browsers/bravo.d.ts +5 -0
- package/dist/browsers/bravo.js +17 -0
- package/dist/browsers/bravo.js.map +1 -0
- package/dist/browsers/chrome.d.ts +5 -0
- package/dist/browsers/chrome.js +17 -0
- package/dist/browsers/chrome.js.map +1 -0
- package/dist/browsers/edge.d.ts +5 -0
- package/dist/browsers/edge.js +17 -0
- package/dist/browsers/edge.js.map +1 -0
- package/dist/browsers/firefoxCookie.d.ts +12 -0
- package/dist/browsers/firefoxCookie.js +8 -0
- package/dist/browsers/firefoxCookie.js.map +1 -0
- package/dist/browsers/opera.d.ts +5 -0
- package/dist/browsers/opera.js +17 -0
- package/dist/browsers/opera.js.map +1 -0
- package/dist/browsers/safariCookie.d.ts +12 -0
- package/dist/browsers/safariCookie.js +8 -0
- package/dist/browsers/safariCookie.js.map +1 -0
- package/dist/browsers/vivaldi.d.ts +5 -0
- package/dist/browsers/vivaldi.js +17 -0
- package/dist/browsers/vivaldi.js.map +1 -0
- package/dist/chromeLinuxCookie.d.ts +5 -0
- package/dist/chromeLinuxCookie.js +12 -0
- package/dist/chromeLinuxCookie.js.map +1 -0
- package/dist/chromeMacCookie.d.ts +5 -0
- package/dist/chromeMacCookie.js +12 -0
- package/dist/chromeMacCookie.js.map +1 -0
- package/dist/chromeWindowsCookie.d.ts +5 -0
- package/dist/chromeWindowsCookie.js +12 -0
- package/dist/chromeWindowsCookie.js.map +1 -0
- package/dist/chunk-2ILP4UJD.js +69 -0
- package/dist/chunk-2ILP4UJD.js.map +1 -0
- package/dist/chunk-4G6NLIPV.js +98 -0
- package/dist/chunk-4G6NLIPV.js.map +1 -0
- package/dist/chunk-5AEUDMIX.js +68 -0
- package/dist/chunk-5AEUDMIX.js.map +1 -0
- package/dist/chunk-5AJFPLWB.js +98 -0
- package/dist/chunk-5AJFPLWB.js.map +1 -0
- package/dist/chunk-6OYYWSIJ.js +58 -0
- package/dist/chunk-6OYYWSIJ.js.map +1 -0
- package/dist/chunk-A3YGBITD.js +221 -0
- package/dist/chunk-A3YGBITD.js.map +1 -0
- package/dist/chunk-AR5Q6KM4.js +37 -0
- package/dist/chunk-AR5Q6KM4.js.map +1 -0
- package/dist/chunk-D23AYBOE.js +35 -0
- package/dist/chunk-D23AYBOE.js.map +1 -0
- package/dist/chunk-E6CQFEXM.js +98 -0
- package/dist/chunk-E6CQFEXM.js.map +1 -0
- package/dist/chunk-EPL3V4O3.js +41 -0
- package/dist/chunk-EPL3V4O3.js.map +1 -0
- package/dist/chunk-EZBYP7NP.js +58 -0
- package/dist/chunk-EZBYP7NP.js.map +1 -0
- package/dist/chunk-GRIZYEBN.js +58 -0
- package/dist/chunk-GRIZYEBN.js.map +1 -0
- package/dist/chunk-HOGGS6QP.js +35 -0
- package/dist/chunk-HOGGS6QP.js.map +1 -0
- package/dist/chunk-IXZPT56H.js +35 -0
- package/dist/chunk-IXZPT56H.js.map +1 -0
- package/dist/chunk-J2UYSXFG.js +69 -0
- package/dist/chunk-J2UYSXFG.js.map +1 -0
- package/dist/chunk-JTBFDYPY.js +244 -0
- package/dist/chunk-JTBFDYPY.js.map +1 -0
- package/dist/chunk-LTLRZZW3.js +41 -0
- package/dist/chunk-LTLRZZW3.js.map +1 -0
- package/dist/chunk-MLKERL3L.js +98 -0
- package/dist/chunk-MLKERL3L.js.map +1 -0
- package/dist/chunk-NGBAATI3.js +35 -0
- package/dist/chunk-NGBAATI3.js.map +1 -0
- package/dist/chunk-PT5JK5UI.js +98 -0
- package/dist/chunk-PT5JK5UI.js.map +1 -0
- package/dist/chunk-Q2LDNBEA.js +35 -0
- package/dist/chunk-Q2LDNBEA.js.map +1 -0
- package/dist/chunk-QCW7AUP6.js +62 -0
- package/dist/chunk-QCW7AUP6.js.map +1 -0
- package/dist/chunk-SRZIPU62.js +69 -0
- package/dist/chunk-SRZIPU62.js.map +1 -0
- package/dist/chunk-SSXWHBKV.js +69 -0
- package/dist/chunk-SSXWHBKV.js.map +1 -0
- package/dist/chunk-TWA6YYS5.js +58 -0
- package/dist/chunk-TWA6YYS5.js.map +1 -0
- package/dist/chunk-TYLH6G3Z.js +52 -0
- package/dist/chunk-TYLH6G3Z.js.map +1 -0
- package/dist/chunk-U4G74MHA.js +69 -0
- package/dist/chunk-U4G74MHA.js.map +1 -0
- package/dist/chunk-UR6BPQ2T.js +103 -0
- package/dist/chunk-UR6BPQ2T.js.map +1 -0
- package/dist/chunk-XDL34EPI.js +35 -0
- package/dist/chunk-XDL34EPI.js.map +1 -0
- package/dist/chunk-YD3PNZMV.js +447 -0
- package/dist/chunk-YD3PNZMV.js.map +1 -0
- package/dist/common.d.ts +15 -0
- package/dist/common.js +9 -0
- package/dist/common.js.map +1 -0
- package/dist/edgeLinuxCookie.d.ts +5 -0
- package/dist/edgeLinuxCookie.js +12 -0
- package/dist/edgeLinuxCookie.js.map +1 -0
- package/dist/edgeMacCookie.d.ts +5 -0
- package/dist/edgeMacCookie.js +12 -0
- package/dist/edgeMacCookie.js.map +1 -0
- package/dist/edgeWindowsCookie.d.ts +5 -0
- package/dist/edgeWindowsCookie.js +12 -0
- package/dist/edgeWindowsCookie.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +38 -0
- package/dist/index.js.map +1 -0
- package/dist/operaLinuxCookie.d.ts +5 -0
- package/dist/operaLinuxCookie.js +12 -0
- package/dist/operaLinuxCookie.js.map +1 -0
- package/dist/operaMacCookie.d.ts +5 -0
- package/dist/operaMacCookie.js +12 -0
- package/dist/operaMacCookie.js.map +1 -0
- package/dist/operaWindowsCookie.d.ts +5 -0
- package/dist/operaWindowsCookie.js +12 -0
- package/dist/operaWindowsCookie.js.map +1 -0
- package/dist/publicApi.d.ts +20 -0
- package/dist/publicApi.js +38 -0
- package/dist/publicApi.js.map +1 -0
- package/dist/types.d.ts +98 -0
- package/dist/types.js +1 -0
- package/dist/types.js.map +1 -0
- package/dist/util/crypto.d.ts +9 -0
- package/dist/util/crypto.js +11 -0
- package/dist/util/crypto.js.map +1 -0
- package/dist/util/fileHelper.d.ts +4 -0
- package/dist/util/fileHelper.js +9 -0
- package/dist/util/fileHelper.js.map +1 -0
- package/dist/util/linuxKeyring.d.ts +11 -0
- package/dist/util/linuxKeyring.js +8 -0
- package/dist/util/linuxKeyring.js.map +1 -0
- package/dist/util/macKeyChain.d.ts +16 -0
- package/dist/util/macKeyChain.js +10 -0
- package/dist/util/macKeyChain.js.map +1 -0
- package/dist/util/processExecutor.d.ts +7 -0
- package/dist/util/processExecutor.js +7 -0
- package/dist/util/processExecutor.js.map +1 -0
- package/dist/util/windowsDpapi.d.ts +9 -0
- package/dist/util/windowsDpapi.js +8 -0
- package/dist/util/windowsDpapi.js.map +1 -0
- package/dist/vivaldiLinuxCookie.d.ts +5 -0
- package/dist/vivaldiLinuxCookie.js +12 -0
- package/dist/vivaldiLinuxCookie.js.map +1 -0
- package/dist/vivaldiMacCookie.d.ts +5 -0
- package/dist/vivaldiMacCookie.js +12 -0
- package/dist/vivaldiMacCookie.js.map +1 -0
- package/dist/vivaldiWindowsCookie.d.ts +5 -0
- package/dist/vivaldiWindowsCookie.js +12 -0
- package/dist/vivaldiWindowsCookie.js.map +1 -0
- package/package.json +56 -0
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import {
|
|
2
|
+
decryptWindowsDpapi
|
|
3
|
+
} from "./chunk-AR5Q6KM4.js";
|
|
4
|
+
import {
|
|
5
|
+
decryptChromiumAES256GCMCookieValue
|
|
6
|
+
} from "./chunk-UR6BPQ2T.js";
|
|
7
|
+
import {
|
|
8
|
+
resolveBrowserDefaultorSpecificDBPath
|
|
9
|
+
} from "./chunk-TYLH6G3Z.js";
|
|
10
|
+
import {
|
|
11
|
+
getCookiesFromChromiumSqliteDB
|
|
12
|
+
} from "./chunk-JTBFDYPY.js";
|
|
13
|
+
|
|
14
|
+
// src/vivaldiWindowsCookie.ts
|
|
15
|
+
import path from "path";
|
|
16
|
+
import { readFileSync } from "fs";
|
|
17
|
+
async function getCookiesFromVivaldiWindowsSqlite(options, origins, cookieNames) {
|
|
18
|
+
const vivaldiUserDataDir = resolveVivaldiWindowsUserDataDir();
|
|
19
|
+
const sqlDBPath = resolveVivaldiWindowsDBPath(vivaldiUserDataDir, options.profile);
|
|
20
|
+
if (!sqlDBPath) {
|
|
21
|
+
return {
|
|
22
|
+
cookies: [],
|
|
23
|
+
warnings: ["Could not resolve Vivaldi cookie database path on Windows."]
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
const warnings = [];
|
|
27
|
+
const keyResult = await extractVivaldiWindowsEncryptionKey(vivaldiUserDataDir);
|
|
28
|
+
if (!keyResult.success) {
|
|
29
|
+
warnings.push(`Failed to get Vivaldi decryption key: ${keyResult.error}`);
|
|
30
|
+
return { cookies: [], warnings };
|
|
31
|
+
}
|
|
32
|
+
const key = keyResult.key;
|
|
33
|
+
const decryptFn = (encryptedValue) => {
|
|
34
|
+
return decryptChromiumAES256GCMCookieValue(encryptedValue, key);
|
|
35
|
+
};
|
|
36
|
+
const fileOptions = {
|
|
37
|
+
cookieFilePath: sqlDBPath
|
|
38
|
+
};
|
|
39
|
+
fileOptions.profile = options.profile;
|
|
40
|
+
fileOptions.includeExpired = options.includeExpired;
|
|
41
|
+
const { cookies, warnings: dbWarnings } = await getCookiesFromChromiumSqliteDB(
|
|
42
|
+
fileOptions,
|
|
43
|
+
origins,
|
|
44
|
+
cookieNames,
|
|
45
|
+
"vivaldi",
|
|
46
|
+
decryptFn
|
|
47
|
+
);
|
|
48
|
+
warnings.push(...dbWarnings);
|
|
49
|
+
return { cookies, warnings };
|
|
50
|
+
}
|
|
51
|
+
function resolveVivaldiWindowsUserDataDir() {
|
|
52
|
+
const localAppData = process.env.LOCALAPPDATA || path.join(process.env.USERPROFILE || "", "AppData", "Local");
|
|
53
|
+
return path.join(localAppData, "Vivaldi", "User Data");
|
|
54
|
+
}
|
|
55
|
+
function resolveVivaldiWindowsDBPath(userDataDir, profile) {
|
|
56
|
+
return resolveBrowserDefaultorSpecificDBPath([userDataDir], profile);
|
|
57
|
+
}
|
|
58
|
+
async function extractVivaldiWindowsEncryptionKey(userDataDir) {
|
|
59
|
+
const localStatePath = path.join(userDataDir, "Local State");
|
|
60
|
+
let localStateContent;
|
|
61
|
+
try {
|
|
62
|
+
localStateContent = readFileSync(localStatePath, "utf8");
|
|
63
|
+
} catch (error) {
|
|
64
|
+
return {
|
|
65
|
+
success: false,
|
|
66
|
+
error: `Failed to read Local State file: ${error.message}`
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
let localState;
|
|
70
|
+
try {
|
|
71
|
+
localState = JSON.parse(localStateContent);
|
|
72
|
+
} catch (error) {
|
|
73
|
+
return {
|
|
74
|
+
success: false,
|
|
75
|
+
error: `Failed to parse Local State JSON: ${error.message}`
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
const encryptedKeyBase64 = localState?.os_crypt?.encrypted_key;
|
|
79
|
+
if (!encryptedKeyBase64) {
|
|
80
|
+
return { success: false, error: "No encrypted_key found in Local State" };
|
|
81
|
+
}
|
|
82
|
+
const encryptedKeyWithPrefix = Buffer.from(encryptedKeyBase64, "base64");
|
|
83
|
+
const dpapiPrefix = encryptedKeyWithPrefix.subarray(0, 5).toString("utf8");
|
|
84
|
+
if (dpapiPrefix !== "DPAPI") {
|
|
85
|
+
return { success: false, error: "Encrypted key does not have expected DPAPI prefix" };
|
|
86
|
+
}
|
|
87
|
+
const encryptedKey = encryptedKeyWithPrefix.subarray(5);
|
|
88
|
+
const dpapiResult = await decryptWindowsDpapi(encryptedKey);
|
|
89
|
+
if (!dpapiResult.success) {
|
|
90
|
+
return { success: false, error: `DPAPI decryption failed: ${dpapiResult.error}` };
|
|
91
|
+
}
|
|
92
|
+
return { success: true, key: dpapiResult.decrypted };
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
export {
|
|
96
|
+
getCookiesFromVivaldiWindowsSqlite
|
|
97
|
+
};
|
|
98
|
+
//# sourceMappingURL=chunk-4G6NLIPV.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/vivaldiWindowsCookie.ts"],"sourcesContent":["import path from 'path';\nimport { readFileSync } from 'fs';\nimport { resolveBrowserDefaultorSpecificDBPath } from './util/fileHelper';\nimport { GetCookiesOptions, GetCookiesResult, GetCookiesFromFileOptions } from './types';\nimport { decryptWindowsDpapi } from './util/windowsDpapi';\nimport { decryptChromiumAES256GCMCookieValue } from './util/crypto';\nimport { getCookiesFromChromiumSqliteDB } from './common';\n\nexport async function getCookiesFromVivaldiWindowsSqlite(\n options: GetCookiesOptions,\n origins: string[],\n cookieNames: Set<string> | null\n): Promise<GetCookiesResult> {\n const vivaldiUserDataDir = resolveVivaldiWindowsUserDataDir();\n const sqlDBPath = resolveVivaldiWindowsDBPath(vivaldiUserDataDir, options.profile);\n if (!sqlDBPath) {\n return {\n cookies: [],\n warnings: ['Could not resolve Vivaldi cookie database path on Windows.'],\n };\n }\n\n const warnings: string[] = [];\n\n const keyResult = await extractVivaldiWindowsEncryptionKey(vivaldiUserDataDir);\n if (!keyResult.success) {\n warnings.push(`Failed to get Vivaldi decryption key: ${keyResult.error}`);\n return { cookies: [], warnings };\n }\n\n const key = keyResult.key;\n const decryptFn = (encryptedValue: Uint8Array): string | null => {\n return decryptChromiumAES256GCMCookieValue(encryptedValue, key);\n };\n\n const fileOptions: GetCookiesFromFileOptions = {\n cookieFilePath: sqlDBPath,\n };\n fileOptions.profile = options.profile;\n fileOptions.includeExpired = options.includeExpired;\n\n const { cookies, warnings: dbWarnings } = await getCookiesFromChromiumSqliteDB(\n fileOptions,\n origins,\n cookieNames,\n 'vivaldi',\n decryptFn\n );\n warnings.push(...dbWarnings);\n\n return { cookies, warnings };\n}\n\nfunction resolveVivaldiWindowsUserDataDir(): string {\n const localAppData =\n process.env.LOCALAPPDATA || path.join(process.env.USERPROFILE || '', 'AppData', 'Local');\n return path.join(localAppData, 'Vivaldi', 'User Data');\n}\n\nfunction resolveVivaldiWindowsDBPath(userDataDir: string, profile?: string): string | null {\n return resolveBrowserDefaultorSpecificDBPath([userDataDir], profile);\n}\n\nasync function extractVivaldiWindowsEncryptionKey(\n userDataDir: string\n): Promise<{ success: true; key: Buffer } | { success: false; error: string }> {\n const localStatePath = path.join(userDataDir, 'Local State');\n\n let localStateContent: string;\n try {\n localStateContent = readFileSync(localStatePath, 'utf8');\n } catch (error) {\n return {\n success: false,\n error: `Failed to read Local State file: ${(error as Error).message}`,\n };\n }\n\n let localState: { os_crypt?: { encrypted_key?: string } };\n try {\n localState = JSON.parse(localStateContent);\n } catch (error) {\n return {\n success: false,\n error: `Failed to parse Local State JSON: ${(error as Error).message}`,\n };\n }\n\n const encryptedKeyBase64 = localState?.os_crypt?.encrypted_key;\n if (!encryptedKeyBase64) {\n return { success: false, error: 'No encrypted_key found in Local State' };\n }\n\n const encryptedKeyWithPrefix = Buffer.from(encryptedKeyBase64, 'base64');\n\n // The key is prefixed with \"DPAPI\" (5 bytes)\n const dpapiPrefix = encryptedKeyWithPrefix.subarray(0, 5).toString('utf8');\n if (dpapiPrefix !== 'DPAPI') {\n return { success: false, error: 'Encrypted key does not have expected DPAPI prefix' };\n }\n\n const encryptedKey = encryptedKeyWithPrefix.subarray(5);\n const dpapiResult = await decryptWindowsDpapi(encryptedKey);\n if (!dpapiResult.success) {\n return { success: false, error: `DPAPI decryption failed: ${dpapiResult.error}` };\n }\n\n return { success: true, key: dpapiResult.decrypted };\n}\n"],"mappings":";;;;;;;;;;;;;;AAAA,OAAO,UAAU;AACjB,SAAS,oBAAoB;AAO7B,eAAsB,mCACpB,SACA,SACA,aAC2B;AAC3B,QAAM,qBAAqB,iCAAiC;AAC5D,QAAM,YAAY,4BAA4B,oBAAoB,QAAQ,OAAO;AACjF,MAAI,CAAC,WAAW;AACd,WAAO;AAAA,MACL,SAAS,CAAC;AAAA,MACV,UAAU,CAAC,4DAA4D;AAAA,IACzE;AAAA,EACF;AAEA,QAAM,WAAqB,CAAC;AAE5B,QAAM,YAAY,MAAM,mCAAmC,kBAAkB;AAC7E,MAAI,CAAC,UAAU,SAAS;AACtB,aAAS,KAAK,yCAAyC,UAAU,KAAK,EAAE;AACxE,WAAO,EAAE,SAAS,CAAC,GAAG,SAAS;AAAA,EACjC;AAEA,QAAM,MAAM,UAAU;AACtB,QAAM,YAAY,CAAC,mBAA8C;AAC/D,WAAO,oCAAoC,gBAAgB,GAAG;AAAA,EAChE;AAEA,QAAM,cAAyC;AAAA,IAC7C,gBAAgB;AAAA,EAClB;AACA,cAAY,UAAU,QAAQ;AAC9B,cAAY,iBAAiB,QAAQ;AAErC,QAAM,EAAE,SAAS,UAAU,WAAW,IAAI,MAAM;AAAA,IAC9C;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACA,WAAS,KAAK,GAAG,UAAU;AAE3B,SAAO,EAAE,SAAS,SAAS;AAC7B;AAEA,SAAS,mCAA2C;AAClD,QAAM,eACJ,QAAQ,IAAI,gBAAgB,KAAK,KAAK,QAAQ,IAAI,eAAe,IAAI,WAAW,OAAO;AACzF,SAAO,KAAK,KAAK,cAAc,WAAW,WAAW;AACvD;AAEA,SAAS,4BAA4B,aAAqB,SAAiC;AACzF,SAAO,sCAAsC,CAAC,WAAW,GAAG,OAAO;AACrE;AAEA,eAAe,mCACb,aAC6E;AAC7E,QAAM,iBAAiB,KAAK,KAAK,aAAa,aAAa;AAE3D,MAAI;AACJ,MAAI;AACF,wBAAoB,aAAa,gBAAgB,MAAM;AAAA,EACzD,SAAS,OAAO;AACd,WAAO;AAAA,MACL,SAAS;AAAA,MACT,OAAO,oCAAqC,MAAgB,OAAO;AAAA,IACrE;AAAA,EACF;AAEA,MAAI;AACJ,MAAI;AACF,iBAAa,KAAK,MAAM,iBAAiB;AAAA,EAC3C,SAAS,OAAO;AACd,WAAO;AAAA,MACL,SAAS;AAAA,MACT,OAAO,qCAAsC,MAAgB,OAAO;AAAA,IACtE;AAAA,EACF;AAEA,QAAM,qBAAqB,YAAY,UAAU;AACjD,MAAI,CAAC,oBAAoB;AACvB,WAAO,EAAE,SAAS,OAAO,OAAO,wCAAwC;AAAA,EAC1E;AAEA,QAAM,yBAAyB,OAAO,KAAK,oBAAoB,QAAQ;AAGvE,QAAM,cAAc,uBAAuB,SAAS,GAAG,CAAC,EAAE,SAAS,MAAM;AACzE,MAAI,gBAAgB,SAAS;AAC3B,WAAO,EAAE,SAAS,OAAO,OAAO,oDAAoD;AAAA,EACtF;AAEA,QAAM,eAAe,uBAAuB,SAAS,CAAC;AACtD,QAAM,cAAc,MAAM,oBAAoB,YAAY;AAC1D,MAAI,CAAC,YAAY,SAAS;AACxB,WAAO,EAAE,SAAS,OAAO,OAAO,4BAA4B,YAAY,KAAK,GAAG;AAAA,EAClF;AAEA,SAAO,EAAE,SAAS,MAAM,KAAK,YAAY,UAAU;AACrD;","names":[]}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import {
|
|
2
|
+
getCookiesFromSafari
|
|
3
|
+
} from "./chunk-A3YGBITD.js";
|
|
4
|
+
import {
|
|
5
|
+
getCookiesFromVivaldi
|
|
6
|
+
} from "./chunk-IXZPT56H.js";
|
|
7
|
+
import {
|
|
8
|
+
getCookiesFromBrave
|
|
9
|
+
} from "./chunk-XDL34EPI.js";
|
|
10
|
+
import {
|
|
11
|
+
getCookiesFromChrome
|
|
12
|
+
} from "./chunk-NGBAATI3.js";
|
|
13
|
+
import {
|
|
14
|
+
getCookiesFromEdge
|
|
15
|
+
} from "./chunk-D23AYBOE.js";
|
|
16
|
+
import {
|
|
17
|
+
getCookiesFromFirefoxSqlite
|
|
18
|
+
} from "./chunk-YD3PNZMV.js";
|
|
19
|
+
import {
|
|
20
|
+
getCookiesFromOpera
|
|
21
|
+
} from "./chunk-HOGGS6QP.js";
|
|
22
|
+
|
|
23
|
+
// src/publicApi.ts
|
|
24
|
+
function toCookieHeader(cookies, options) {
|
|
25
|
+
const items = cookies.map((cookie) => ({ name: cookie.name, value: cookie.value }));
|
|
26
|
+
if (options.sortByName) {
|
|
27
|
+
items.sort((a, b) => a.name.localeCompare(b.name));
|
|
28
|
+
}
|
|
29
|
+
if (options.removeDuplicates) {
|
|
30
|
+
const seen = /* @__PURE__ */ new Set();
|
|
31
|
+
const uniqueItems = [];
|
|
32
|
+
for (const item of items) {
|
|
33
|
+
if (!seen.has(item.name)) {
|
|
34
|
+
seen.add(item.name);
|
|
35
|
+
uniqueItems.push(item);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
return uniqueItems.map((item) => `${item.name}=${item.value}`).join("; ");
|
|
39
|
+
}
|
|
40
|
+
return items.map((item) => `${item.name}=${item.value}`).join("; ");
|
|
41
|
+
}
|
|
42
|
+
async function getCookiesFromBrowser(params) {
|
|
43
|
+
const { origins, cookieNames, browserName, profile, includeExpired, includePartitioned } = params;
|
|
44
|
+
const cookieNamesSet = cookieNames ? new Set(cookieNames) : null;
|
|
45
|
+
const options = { profile, includeExpired, includePartitioned };
|
|
46
|
+
switch (browserName) {
|
|
47
|
+
case "chrome":
|
|
48
|
+
return getCookiesFromChrome(options, origins, cookieNamesSet);
|
|
49
|
+
case "edge":
|
|
50
|
+
return getCookiesFromEdge(options, origins, cookieNamesSet);
|
|
51
|
+
case "firefox":
|
|
52
|
+
return getCookiesFromFirefoxSqlite(options, origins, cookieNamesSet);
|
|
53
|
+
case "safari":
|
|
54
|
+
return getCookiesFromSafari(options, origins, cookieNamesSet);
|
|
55
|
+
case "opera":
|
|
56
|
+
return getCookiesFromOpera(options, origins, cookieNamesSet);
|
|
57
|
+
case "brave":
|
|
58
|
+
return getCookiesFromBrave(options, origins, cookieNamesSet);
|
|
59
|
+
case "vivaldi":
|
|
60
|
+
return getCookiesFromVivaldi(options, origins, cookieNamesSet);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
export {
|
|
65
|
+
toCookieHeader,
|
|
66
|
+
getCookiesFromBrowser
|
|
67
|
+
};
|
|
68
|
+
//# sourceMappingURL=chunk-5AEUDMIX.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/publicApi.ts"],"sourcesContent":["import {\n Cookie,\n CookieHeaderOption,\n GetCookiesOptions,\n GetCookiesResult,\n GetCookiesFromBrowserParams,\n} from './types';\nimport { getCookiesFromChrome } from './browsers/chrome';\nimport { getCookiesFromEdge } from './browsers/edge';\nimport { getCookiesFromFirefoxSqlite } from './browsers/firefoxCookie';\nimport { getCookiesFromSafari } from './browsers/safariCookie';\nimport { getCookiesFromOpera } from './browsers/opera';\nimport { getCookiesFromBrave } from './browsers/bravo';\nimport { getCookiesFromVivaldi } from './browsers/vivaldi';\n\n/**\n * Convert an array of Cookie objects into a Cookie header string (e.g. \"name1=value1; name2=value2\")\n * @param cookies - The cookies to serialize\n * @param options - Options for formatting the header\n * - removeDuplicates: keep only the first occurrence of each cookie name\n * - sortByName: sort cookies alphabetically by name\n * @returns A formatted Cookie header string\n */\nexport function toCookieHeader(cookies: Cookie[], options: CookieHeaderOption): string {\n const items = cookies.map((cookie) => ({ name: cookie.name, value: cookie.value }));\n if (options.sortByName) {\n items.sort((a, b) => a.name.localeCompare(b.name));\n }\n\n if (options.removeDuplicates) {\n const seen = new Set<string>();\n const uniqueItems = [];\n for (const item of items) {\n if (!seen.has(item.name)) {\n seen.add(item.name);\n uniqueItems.push(item);\n }\n }\n return uniqueItems.map((item) => `${item.name}=${item.value}`).join('; ');\n }\n return items.map((item) => `${item.name}=${item.value}`).join('; ');\n}\n\n/**\n * Extract cookies from a specified browser's local storage.\n * Supports Chrome, Edge, Firefox, Safari, Opera, Brave and Vivaldi.\n * @param params - Browser and filtering options\n * @returns Extracted cookies and any warnings encountered during parsing\n */\nexport async function getCookiesFromBrowser(\n params: GetCookiesFromBrowserParams,\n): Promise<GetCookiesResult> {\n const { origins, cookieNames, browserName, profile, includeExpired, includePartitioned } = params;\n const cookieNamesSet = cookieNames ? new Set(cookieNames) : null;\n const options: GetCookiesOptions = { profile, includeExpired, includePartitioned };\n\n switch (browserName) {\n case 'chrome':\n return getCookiesFromChrome(options, origins, cookieNamesSet);\n case 'edge':\n return getCookiesFromEdge(options, origins, cookieNamesSet);\n case 'firefox':\n return getCookiesFromFirefoxSqlite(options, origins, cookieNamesSet);\n case 'safari':\n return getCookiesFromSafari(options, origins, cookieNamesSet);\n case 'opera':\n return getCookiesFromOpera(options, origins, cookieNamesSet);\n case 'brave':\n return getCookiesFromBrave(options, origins, cookieNamesSet);\n case 'vivaldi':\n return getCookiesFromVivaldi(options, origins, cookieNamesSet);\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;AAuBO,SAAS,eAAe,SAAmB,SAAqC;AACrF,QAAM,QAAQ,QAAQ,IAAI,CAAC,YAAY,EAAE,MAAM,OAAO,MAAM,OAAO,OAAO,MAAM,EAAE;AAClF,MAAI,QAAQ,YAAY;AACtB,UAAM,KAAK,CAAC,GAAG,MAAM,EAAE,KAAK,cAAc,EAAE,IAAI,CAAC;AAAA,EACnD;AAEA,MAAI,QAAQ,kBAAkB;AAC5B,UAAM,OAAO,oBAAI,IAAY;AAC7B,UAAM,cAAc,CAAC;AACrB,eAAW,QAAQ,OAAO;AACxB,UAAI,CAAC,KAAK,IAAI,KAAK,IAAI,GAAG;AACxB,aAAK,IAAI,KAAK,IAAI;AAClB,oBAAY,KAAK,IAAI;AAAA,MACvB;AAAA,IACF;AACA,WAAO,YAAY,IAAI,CAAC,SAAS,GAAG,KAAK,IAAI,IAAI,KAAK,KAAK,EAAE,EAAE,KAAK,IAAI;AAAA,EAC1E;AACA,SAAO,MAAM,IAAI,CAAC,SAAS,GAAG,KAAK,IAAI,IAAI,KAAK,KAAK,EAAE,EAAE,KAAK,IAAI;AACpE;AAQA,eAAsB,sBACpB,QAC2B;AAC3B,QAAM,EAAE,SAAS,aAAa,aAAa,SAAS,gBAAgB,mBAAmB,IAAI;AAC3F,QAAM,iBAAiB,cAAc,IAAI,IAAI,WAAW,IAAI;AAC5D,QAAM,UAA6B,EAAE,SAAS,gBAAgB,mBAAmB;AAEjF,UAAQ,aAAa;AAAA,IACnB,KAAK;AACH,aAAO,qBAAqB,SAAS,SAAS,cAAc;AAAA,IAC9D,KAAK;AACH,aAAO,mBAAmB,SAAS,SAAS,cAAc;AAAA,IAC5D,KAAK;AACH,aAAO,4BAA4B,SAAS,SAAS,cAAc;AAAA,IACrE,KAAK;AACH,aAAO,qBAAqB,SAAS,SAAS,cAAc;AAAA,IAC9D,KAAK;AACH,aAAO,oBAAoB,SAAS,SAAS,cAAc;AAAA,IAC7D,KAAK;AACH,aAAO,oBAAoB,SAAS,SAAS,cAAc;AAAA,IAC7D,KAAK;AACH,aAAO,sBAAsB,SAAS,SAAS,cAAc;AAAA,EACjE;AACF;","names":[]}
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import {
|
|
2
|
+
decryptWindowsDpapi
|
|
3
|
+
} from "./chunk-AR5Q6KM4.js";
|
|
4
|
+
import {
|
|
5
|
+
decryptChromiumAES256GCMCookieValue
|
|
6
|
+
} from "./chunk-UR6BPQ2T.js";
|
|
7
|
+
import {
|
|
8
|
+
resolveBrowserDefaultorSpecificDBPath
|
|
9
|
+
} from "./chunk-TYLH6G3Z.js";
|
|
10
|
+
import {
|
|
11
|
+
getCookiesFromChromiumSqliteDB
|
|
12
|
+
} from "./chunk-JTBFDYPY.js";
|
|
13
|
+
|
|
14
|
+
// src/operaWindowsCookie.ts
|
|
15
|
+
import path from "path";
|
|
16
|
+
import { readFileSync } from "fs";
|
|
17
|
+
async function getCookiesFromOperaWindowsSqlite(options, origins, cookieNames) {
|
|
18
|
+
const operaUserDataDir = resolveOperaWindowsUserDataDir();
|
|
19
|
+
const sqlDBPath = resolveOperaWindowsDBPath(operaUserDataDir, options.profile);
|
|
20
|
+
if (!sqlDBPath) {
|
|
21
|
+
return {
|
|
22
|
+
cookies: [],
|
|
23
|
+
warnings: ["Could not resolve Opera cookie database path on Windows."]
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
const warnings = [];
|
|
27
|
+
const keyResult = await extractOperaWindowsEncryptionKey(operaUserDataDir);
|
|
28
|
+
if (!keyResult.success) {
|
|
29
|
+
warnings.push(`Failed to get Opera decryption key: ${keyResult.error}`);
|
|
30
|
+
return { cookies: [], warnings };
|
|
31
|
+
}
|
|
32
|
+
const key = keyResult.key;
|
|
33
|
+
const decryptFn = (encryptedValue) => {
|
|
34
|
+
return decryptChromiumAES256GCMCookieValue(encryptedValue, key);
|
|
35
|
+
};
|
|
36
|
+
const fileOptions = {
|
|
37
|
+
cookieFilePath: sqlDBPath
|
|
38
|
+
};
|
|
39
|
+
fileOptions.profile = options.profile;
|
|
40
|
+
fileOptions.includeExpired = options.includeExpired;
|
|
41
|
+
const { cookies, warnings: dbWarnings } = await getCookiesFromChromiumSqliteDB(
|
|
42
|
+
fileOptions,
|
|
43
|
+
origins,
|
|
44
|
+
cookieNames,
|
|
45
|
+
"opera",
|
|
46
|
+
decryptFn
|
|
47
|
+
);
|
|
48
|
+
warnings.push(...dbWarnings);
|
|
49
|
+
return { cookies, warnings };
|
|
50
|
+
}
|
|
51
|
+
function resolveOperaWindowsUserDataDir() {
|
|
52
|
+
const appData = process.env.APPDATA || path.join(process.env.USERPROFILE || "", "AppData", "Roaming");
|
|
53
|
+
return path.join(appData, "Opera Software", "Opera Stable");
|
|
54
|
+
}
|
|
55
|
+
function resolveOperaWindowsDBPath(userDataDir, profile) {
|
|
56
|
+
return resolveBrowserDefaultorSpecificDBPath([userDataDir], profile);
|
|
57
|
+
}
|
|
58
|
+
async function extractOperaWindowsEncryptionKey(userDataDir) {
|
|
59
|
+
const localStatePath = path.join(userDataDir, "Local State");
|
|
60
|
+
let localStateContent;
|
|
61
|
+
try {
|
|
62
|
+
localStateContent = readFileSync(localStatePath, "utf8");
|
|
63
|
+
} catch (error) {
|
|
64
|
+
return {
|
|
65
|
+
success: false,
|
|
66
|
+
error: `Failed to read Local State file: ${error.message}`
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
let localState;
|
|
70
|
+
try {
|
|
71
|
+
localState = JSON.parse(localStateContent);
|
|
72
|
+
} catch (error) {
|
|
73
|
+
return {
|
|
74
|
+
success: false,
|
|
75
|
+
error: `Failed to parse Local State JSON: ${error.message}`
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
const encryptedKeyBase64 = localState?.os_crypt?.encrypted_key;
|
|
79
|
+
if (!encryptedKeyBase64) {
|
|
80
|
+
return { success: false, error: "No encrypted_key found in Local State" };
|
|
81
|
+
}
|
|
82
|
+
const encryptedKeyWithPrefix = Buffer.from(encryptedKeyBase64, "base64");
|
|
83
|
+
const dpapiPrefix = encryptedKeyWithPrefix.subarray(0, 5).toString("utf8");
|
|
84
|
+
if (dpapiPrefix !== "DPAPI") {
|
|
85
|
+
return { success: false, error: "Encrypted key does not have expected DPAPI prefix" };
|
|
86
|
+
}
|
|
87
|
+
const encryptedKey = encryptedKeyWithPrefix.subarray(5);
|
|
88
|
+
const dpapiResult = await decryptWindowsDpapi(encryptedKey);
|
|
89
|
+
if (!dpapiResult.success) {
|
|
90
|
+
return { success: false, error: `DPAPI decryption failed: ${dpapiResult.error}` };
|
|
91
|
+
}
|
|
92
|
+
return { success: true, key: dpapiResult.decrypted };
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
export {
|
|
96
|
+
getCookiesFromOperaWindowsSqlite
|
|
97
|
+
};
|
|
98
|
+
//# sourceMappingURL=chunk-5AJFPLWB.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/operaWindowsCookie.ts"],"sourcesContent":["import path from 'path';\nimport { readFileSync } from 'fs';\nimport { resolveBrowserDefaultorSpecificDBPath } from './util/fileHelper';\nimport { GetCookiesOptions, GetCookiesResult, GetCookiesFromFileOptions } from './types';\nimport { decryptWindowsDpapi } from './util/windowsDpapi';\nimport { decryptChromiumAES256GCMCookieValue } from './util/crypto';\nimport { getCookiesFromChromiumSqliteDB } from './common';\n\nexport async function getCookiesFromOperaWindowsSqlite(\n options: GetCookiesOptions,\n origins: string[],\n cookieNames: Set<string> | null\n): Promise<GetCookiesResult> {\n const operaUserDataDir = resolveOperaWindowsUserDataDir();\n const sqlDBPath = resolveOperaWindowsDBPath(operaUserDataDir, options.profile);\n if (!sqlDBPath) {\n return {\n cookies: [],\n warnings: ['Could not resolve Opera cookie database path on Windows.'],\n };\n }\n\n const warnings: string[] = [];\n\n const keyResult = await extractOperaWindowsEncryptionKey(operaUserDataDir);\n if (!keyResult.success) {\n warnings.push(`Failed to get Opera decryption key: ${keyResult.error}`);\n return { cookies: [], warnings };\n }\n\n const key = keyResult.key;\n const decryptFn = (encryptedValue: Uint8Array): string | null => {\n return decryptChromiumAES256GCMCookieValue(encryptedValue, key);\n };\n\n const fileOptions: GetCookiesFromFileOptions = {\n cookieFilePath: sqlDBPath,\n };\n fileOptions.profile = options.profile;\n fileOptions.includeExpired = options.includeExpired;\n\n const { cookies, warnings: dbWarnings } = await getCookiesFromChromiumSqliteDB(\n fileOptions,\n origins,\n cookieNames,\n 'opera',\n decryptFn\n );\n warnings.push(...dbWarnings);\n\n return { cookies, warnings };\n}\n\nfunction resolveOperaWindowsUserDataDir(): string {\n const appData =\n process.env.APPDATA || path.join(process.env.USERPROFILE || '', 'AppData', 'Roaming');\n return path.join(appData, 'Opera Software', 'Opera Stable');\n}\n\nfunction resolveOperaWindowsDBPath(userDataDir: string, profile?: string): string | null {\n return resolveBrowserDefaultorSpecificDBPath([userDataDir], profile);\n}\n\nasync function extractOperaWindowsEncryptionKey(\n userDataDir: string\n): Promise<{ success: true; key: Buffer } | { success: false; error: string }> {\n const localStatePath = path.join(userDataDir, 'Local State');\n\n let localStateContent: string;\n try {\n localStateContent = readFileSync(localStatePath, 'utf8');\n } catch (error) {\n return {\n success: false,\n error: `Failed to read Local State file: ${(error as Error).message}`,\n };\n }\n\n let localState: { os_crypt?: { encrypted_key?: string } };\n try {\n localState = JSON.parse(localStateContent);\n } catch (error) {\n return {\n success: false,\n error: `Failed to parse Local State JSON: ${(error as Error).message}`,\n };\n }\n\n const encryptedKeyBase64 = localState?.os_crypt?.encrypted_key;\n if (!encryptedKeyBase64) {\n return { success: false, error: 'No encrypted_key found in Local State' };\n }\n\n const encryptedKeyWithPrefix = Buffer.from(encryptedKeyBase64, 'base64');\n\n // The key is prefixed with \"DPAPI\" (5 bytes)\n const dpapiPrefix = encryptedKeyWithPrefix.subarray(0, 5).toString('utf8');\n if (dpapiPrefix !== 'DPAPI') {\n return { success: false, error: 'Encrypted key does not have expected DPAPI prefix' };\n }\n\n const encryptedKey = encryptedKeyWithPrefix.subarray(5);\n const dpapiResult = await decryptWindowsDpapi(encryptedKey);\n if (!dpapiResult.success) {\n return { success: false, error: `DPAPI decryption failed: ${dpapiResult.error}` };\n }\n\n return { success: true, key: dpapiResult.decrypted };\n}\n"],"mappings":";;;;;;;;;;;;;;AAAA,OAAO,UAAU;AACjB,SAAS,oBAAoB;AAO7B,eAAsB,iCACpB,SACA,SACA,aAC2B;AAC3B,QAAM,mBAAmB,+BAA+B;AACxD,QAAM,YAAY,0BAA0B,kBAAkB,QAAQ,OAAO;AAC7E,MAAI,CAAC,WAAW;AACd,WAAO;AAAA,MACL,SAAS,CAAC;AAAA,MACV,UAAU,CAAC,0DAA0D;AAAA,IACvE;AAAA,EACF;AAEA,QAAM,WAAqB,CAAC;AAE5B,QAAM,YAAY,MAAM,iCAAiC,gBAAgB;AACzE,MAAI,CAAC,UAAU,SAAS;AACtB,aAAS,KAAK,uCAAuC,UAAU,KAAK,EAAE;AACtE,WAAO,EAAE,SAAS,CAAC,GAAG,SAAS;AAAA,EACjC;AAEA,QAAM,MAAM,UAAU;AACtB,QAAM,YAAY,CAAC,mBAA8C;AAC/D,WAAO,oCAAoC,gBAAgB,GAAG;AAAA,EAChE;AAEA,QAAM,cAAyC;AAAA,IAC7C,gBAAgB;AAAA,EAClB;AACA,cAAY,UAAU,QAAQ;AAC9B,cAAY,iBAAiB,QAAQ;AAErC,QAAM,EAAE,SAAS,UAAU,WAAW,IAAI,MAAM;AAAA,IAC9C;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACA,WAAS,KAAK,GAAG,UAAU;AAE3B,SAAO,EAAE,SAAS,SAAS;AAC7B;AAEA,SAAS,iCAAyC;AAChD,QAAM,UACJ,QAAQ,IAAI,WAAW,KAAK,KAAK,QAAQ,IAAI,eAAe,IAAI,WAAW,SAAS;AACtF,SAAO,KAAK,KAAK,SAAS,kBAAkB,cAAc;AAC5D;AAEA,SAAS,0BAA0B,aAAqB,SAAiC;AACvF,SAAO,sCAAsC,CAAC,WAAW,GAAG,OAAO;AACrE;AAEA,eAAe,iCACb,aAC6E;AAC7E,QAAM,iBAAiB,KAAK,KAAK,aAAa,aAAa;AAE3D,MAAI;AACJ,MAAI;AACF,wBAAoB,aAAa,gBAAgB,MAAM;AAAA,EACzD,SAAS,OAAO;AACd,WAAO;AAAA,MACL,SAAS;AAAA,MACT,OAAO,oCAAqC,MAAgB,OAAO;AAAA,IACrE;AAAA,EACF;AAEA,MAAI;AACJ,MAAI;AACF,iBAAa,KAAK,MAAM,iBAAiB;AAAA,EAC3C,SAAS,OAAO;AACd,WAAO;AAAA,MACL,SAAS;AAAA,MACT,OAAO,qCAAsC,MAAgB,OAAO;AAAA,IACtE;AAAA,EACF;AAEA,QAAM,qBAAqB,YAAY,UAAU;AACjD,MAAI,CAAC,oBAAoB;AACvB,WAAO,EAAE,SAAS,OAAO,OAAO,wCAAwC;AAAA,EAC1E;AAEA,QAAM,yBAAyB,OAAO,KAAK,oBAAoB,QAAQ;AAGvE,QAAM,cAAc,uBAAuB,SAAS,GAAG,CAAC,EAAE,SAAS,MAAM;AACzE,MAAI,gBAAgB,SAAS;AAC3B,WAAO,EAAE,SAAS,OAAO,OAAO,oDAAoD;AAAA,EACtF;AAEA,QAAM,eAAe,uBAAuB,SAAS,CAAC;AACtD,QAAM,cAAc,MAAM,oBAAoB,YAAY;AAC1D,MAAI,CAAC,YAAY,SAAS;AACxB,WAAO,EAAE,SAAS,OAAO,OAAO,4BAA4B,YAAY,KAAK,GAAG;AAAA,EAClF;AAEA,SAAO,EAAE,SAAS,MAAM,KAAK,YAAY,UAAU;AACrD;","names":[]}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import {
|
|
2
|
+
findLinuxChromiumPassword
|
|
3
|
+
} from "./chunk-EPL3V4O3.js";
|
|
4
|
+
import {
|
|
5
|
+
decryptChomiumAES128CBCCookieValue,
|
|
6
|
+
getAES128CBCKey
|
|
7
|
+
} from "./chunk-UR6BPQ2T.js";
|
|
8
|
+
import {
|
|
9
|
+
resolveBrowserDefaultorSpecificDBPath
|
|
10
|
+
} from "./chunk-TYLH6G3Z.js";
|
|
11
|
+
import {
|
|
12
|
+
getCookiesFromChromiumSqliteDB
|
|
13
|
+
} from "./chunk-JTBFDYPY.js";
|
|
14
|
+
|
|
15
|
+
// src/chromeLinuxCookie.ts
|
|
16
|
+
import { homedir } from "os";
|
|
17
|
+
async function getCookiesFromChromeLinuxSqlite(options, origins, cookieNames) {
|
|
18
|
+
const sqlDBPath = resolveChromeLinuxDBPath(options.profile);
|
|
19
|
+
if (!sqlDBPath) {
|
|
20
|
+
return {
|
|
21
|
+
cookies: [],
|
|
22
|
+
warnings: ["Could not resolve Chrome cookie database path on Linux."]
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
const warnings = [];
|
|
26
|
+
const passwordResult = await findLinuxChromiumPassword("chrome", "Chrome Safe Storage", 5e3);
|
|
27
|
+
if (passwordResult.warnings.length > 0) {
|
|
28
|
+
warnings.push(...passwordResult.warnings);
|
|
29
|
+
}
|
|
30
|
+
const key = getAES128CBCKey(passwordResult.password, 1);
|
|
31
|
+
const decryptFn = (encryptedValue) => {
|
|
32
|
+
return decryptChomiumAES128CBCCookieValue(encryptedValue, [key]);
|
|
33
|
+
};
|
|
34
|
+
const fileOptions = {
|
|
35
|
+
cookieFilePath: sqlDBPath
|
|
36
|
+
};
|
|
37
|
+
fileOptions.profile = options.profile;
|
|
38
|
+
fileOptions.includeExpired = options.includeExpired;
|
|
39
|
+
const { cookies, warnings: dbWarnings } = await getCookiesFromChromiumSqliteDB(
|
|
40
|
+
fileOptions,
|
|
41
|
+
origins,
|
|
42
|
+
cookieNames,
|
|
43
|
+
"chrome",
|
|
44
|
+
decryptFn
|
|
45
|
+
);
|
|
46
|
+
warnings.push(...dbWarnings);
|
|
47
|
+
return { cookies, warnings };
|
|
48
|
+
}
|
|
49
|
+
function resolveChromeLinuxDBPath(profile) {
|
|
50
|
+
const homeDir = homedir();
|
|
51
|
+
const roots = [`${homeDir}/.config/google-chrome`];
|
|
52
|
+
return resolveBrowserDefaultorSpecificDBPath(roots, profile);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export {
|
|
56
|
+
getCookiesFromChromeLinuxSqlite
|
|
57
|
+
};
|
|
58
|
+
//# sourceMappingURL=chunk-6OYYWSIJ.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/chromeLinuxCookie.ts"],"sourcesContent":["import { homedir } from 'os';\nimport { resolveBrowserDefaultorSpecificDBPath } from './util/fileHelper';\nimport { GetCookiesOptions, GetCookiesResult, GetCookiesFromFileOptions } from './types';\nimport { getAES128CBCKey, decryptChomiumAES128CBCCookieValue } from './util/crypto';\nimport { getCookiesFromChromiumSqliteDB } from './common';\nimport { findLinuxChromiumPassword } from './util/linuxKeyring';\n\nexport async function getCookiesFromChromeLinuxSqlite(\n options: GetCookiesOptions,\n origins: string[],\n cookieNames: Set<string> | null\n): Promise<GetCookiesResult> {\n const sqlDBPath = resolveChromeLinuxDBPath(options.profile);\n if (!sqlDBPath) {\n return {\n cookies: [],\n warnings: ['Could not resolve Chrome cookie database path on Linux.'],\n };\n }\n\n const warnings: string[] = [];\n\n const passwordResult = await findLinuxChromiumPassword('chrome', 'Chrome Safe Storage', 5000);\n if (passwordResult.warnings.length > 0) {\n warnings.push(...passwordResult.warnings);\n }\n\n // iterations is 1 for Linux Chrome\n const key = getAES128CBCKey(passwordResult.password, 1);\n const decryptFn = (encryptedValue: Uint8Array): string | null => {\n return decryptChomiumAES128CBCCookieValue(encryptedValue, [key]);\n };\n\n const fileOptions: GetCookiesFromFileOptions = {\n cookieFilePath: sqlDBPath,\n };\n fileOptions.profile = options.profile;\n fileOptions.includeExpired = options.includeExpired;\n\n const { cookies, warnings: dbWarnings } = await getCookiesFromChromiumSqliteDB(\n fileOptions,\n origins,\n cookieNames,\n 'chrome',\n decryptFn\n );\n warnings.push(...dbWarnings);\n\n return { cookies, warnings };\n}\n\nfunction resolveChromeLinuxDBPath(profile?: string): string | null {\n const homeDir = homedir();\n const roots = [`${homeDir}/.config/google-chrome`];\n return resolveBrowserDefaultorSpecificDBPath(roots, profile);\n}\n"],"mappings":";;;;;;;;;;;;;;;AAAA,SAAS,eAAe;AAOxB,eAAsB,gCACpB,SACA,SACA,aAC2B;AAC3B,QAAM,YAAY,yBAAyB,QAAQ,OAAO;AAC1D,MAAI,CAAC,WAAW;AACd,WAAO;AAAA,MACL,SAAS,CAAC;AAAA,MACV,UAAU,CAAC,yDAAyD;AAAA,IACtE;AAAA,EACF;AAEA,QAAM,WAAqB,CAAC;AAE5B,QAAM,iBAAiB,MAAM,0BAA0B,UAAU,uBAAuB,GAAI;AAC5F,MAAI,eAAe,SAAS,SAAS,GAAG;AACtC,aAAS,KAAK,GAAG,eAAe,QAAQ;AAAA,EAC1C;AAGA,QAAM,MAAM,gBAAgB,eAAe,UAAU,CAAC;AACtD,QAAM,YAAY,CAAC,mBAA8C;AAC/D,WAAO,mCAAmC,gBAAgB,CAAC,GAAG,CAAC;AAAA,EACjE;AAEA,QAAM,cAAyC;AAAA,IAC7C,gBAAgB;AAAA,EAClB;AACA,cAAY,UAAU,QAAQ;AAC9B,cAAY,iBAAiB,QAAQ;AAErC,QAAM,EAAE,SAAS,UAAU,WAAW,IAAI,MAAM;AAAA,IAC9C;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACA,WAAS,KAAK,GAAG,UAAU;AAE3B,SAAO,EAAE,SAAS,SAAS;AAC7B;AAEA,SAAS,yBAAyB,SAAiC;AACjE,QAAM,UAAU,QAAQ;AACxB,QAAM,QAAQ,CAAC,GAAG,OAAO,wBAAwB;AACjD,SAAO,sCAAsC,OAAO,OAAO;AAC7D;","names":[]}
|
|
@@ -0,0 +1,221 @@
|
|
|
1
|
+
import {
|
|
2
|
+
normalizeExpiration
|
|
3
|
+
} from "./chunk-JTBFDYPY.js";
|
|
4
|
+
|
|
5
|
+
// src/browsers/safariCookie.ts
|
|
6
|
+
import { homedir, tmpdir } from "os";
|
|
7
|
+
import { copyFileSync, mkdtempSync, rmSync, existsSync, readFileSync, statSync } from "fs";
|
|
8
|
+
import path from "path";
|
|
9
|
+
var BINARY_COOKIES_MAGIC = "cook";
|
|
10
|
+
async function getCookiesFromSafari(options, origins, cookieNames) {
|
|
11
|
+
const warnings = [];
|
|
12
|
+
if (process.platform !== "darwin") {
|
|
13
|
+
warnings.push("Safari cookies are only supported on macOS.");
|
|
14
|
+
return { cookies: [], warnings };
|
|
15
|
+
}
|
|
16
|
+
let hosts;
|
|
17
|
+
try {
|
|
18
|
+
hosts = origins.map((origin) => new URL(origin).hostname);
|
|
19
|
+
} catch (error) {
|
|
20
|
+
warnings.push(`Invalid URL: ${error.message}`);
|
|
21
|
+
return { cookies: [], warnings };
|
|
22
|
+
}
|
|
23
|
+
const cookieFilePath = resolveSafariCookiePath(options.profile);
|
|
24
|
+
if (!cookieFilePath) {
|
|
25
|
+
warnings.push("Could not find Safari cookie file.");
|
|
26
|
+
return { cookies: [], warnings };
|
|
27
|
+
}
|
|
28
|
+
const tmpdirPath = mkdtempSync(path.join(tmpdir(), "sqlite-cookie-safari-"));
|
|
29
|
+
const tempFilePath = path.join(tmpdirPath, "Cookies.binarycookies");
|
|
30
|
+
try {
|
|
31
|
+
copyFileSync(cookieFilePath, tempFilePath);
|
|
32
|
+
} catch (error) {
|
|
33
|
+
rmSync(tmpdirPath, { recursive: true, force: true });
|
|
34
|
+
warnings.push(`Failed to copy Safari cookie file: ${error.message}`);
|
|
35
|
+
return { cookies: [], warnings };
|
|
36
|
+
}
|
|
37
|
+
try {
|
|
38
|
+
const fileBuffer = readFileSync(tempFilePath);
|
|
39
|
+
const rawCookies = parseBinaryCookies(fileBuffer);
|
|
40
|
+
const fileOptions = {
|
|
41
|
+
cookieFilePath,
|
|
42
|
+
profile: options.profile,
|
|
43
|
+
includeExpired: options.includeExpired
|
|
44
|
+
};
|
|
45
|
+
const cookies = filterAndConvertCookies(rawCookies, fileOptions, hosts, cookieNames);
|
|
46
|
+
rmSync(tmpdirPath, { recursive: true, force: true });
|
|
47
|
+
if (cookies.length === 0 && warnings.length === 0) {
|
|
48
|
+
warnings.push("No cookies found.");
|
|
49
|
+
}
|
|
50
|
+
return { cookies, warnings };
|
|
51
|
+
} catch (error) {
|
|
52
|
+
rmSync(tmpdirPath, { recursive: true, force: true });
|
|
53
|
+
warnings.push(`Failed to parse Safari cookie file: ${error.message}`);
|
|
54
|
+
return { cookies: [], warnings };
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
function parseBinaryCookies(buffer) {
|
|
58
|
+
let offset = 0;
|
|
59
|
+
const magic = buffer.subarray(0, 4).toString("ascii");
|
|
60
|
+
if (magic !== BINARY_COOKIES_MAGIC) {
|
|
61
|
+
throw new Error(
|
|
62
|
+
`Invalid BinaryCookies magic: expected "${BINARY_COOKIES_MAGIC}", got "${magic}"`
|
|
63
|
+
);
|
|
64
|
+
}
|
|
65
|
+
offset = 4;
|
|
66
|
+
const numPages = buffer.readUInt32BE(offset);
|
|
67
|
+
offset += 4;
|
|
68
|
+
const pageSizes = [];
|
|
69
|
+
for (let i = 0; i < numPages; i++) {
|
|
70
|
+
pageSizes.push(buffer.readUInt32BE(offset));
|
|
71
|
+
offset += 4;
|
|
72
|
+
}
|
|
73
|
+
const cookies = [];
|
|
74
|
+
for (let i = 0; i < numPages; i++) {
|
|
75
|
+
const pageStart = offset;
|
|
76
|
+
const pageBuffer = buffer.subarray(pageStart, pageStart + pageSizes[i]);
|
|
77
|
+
const pageCookies = parsePage(pageBuffer);
|
|
78
|
+
cookies.push(...pageCookies);
|
|
79
|
+
offset += pageSizes[i];
|
|
80
|
+
}
|
|
81
|
+
return cookies;
|
|
82
|
+
}
|
|
83
|
+
function parsePage(page) {
|
|
84
|
+
let offset = 0;
|
|
85
|
+
offset += 4;
|
|
86
|
+
const numCookies = page.readUInt32LE(offset);
|
|
87
|
+
offset += 4;
|
|
88
|
+
const cookieOffsets = [];
|
|
89
|
+
for (let i = 0; i < numCookies; i++) {
|
|
90
|
+
cookieOffsets.push(page.readUInt32LE(offset));
|
|
91
|
+
offset += 4;
|
|
92
|
+
}
|
|
93
|
+
const cookies = [];
|
|
94
|
+
for (const cookieOffset of cookieOffsets) {
|
|
95
|
+
try {
|
|
96
|
+
const cookie = parseCookieRecord(page, cookieOffset);
|
|
97
|
+
if (cookie) {
|
|
98
|
+
cookies.push(cookie);
|
|
99
|
+
}
|
|
100
|
+
} catch {
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
return cookies;
|
|
104
|
+
}
|
|
105
|
+
function parseCookieRecord(page, startOffset) {
|
|
106
|
+
let offset = startOffset;
|
|
107
|
+
offset += 4;
|
|
108
|
+
const flags = page.readUInt32LE(offset);
|
|
109
|
+
offset += 4;
|
|
110
|
+
offset += 8;
|
|
111
|
+
const urlOffset = page.readUInt32LE(offset);
|
|
112
|
+
offset += 4;
|
|
113
|
+
const nameOffset = page.readUInt32LE(offset);
|
|
114
|
+
offset += 4;
|
|
115
|
+
const pathOffset = page.readUInt32LE(offset);
|
|
116
|
+
offset += 4;
|
|
117
|
+
const valueOffset = page.readUInt32LE(offset);
|
|
118
|
+
offset += 4;
|
|
119
|
+
offset += 8;
|
|
120
|
+
const expiry = page.readDoubleLE(offset);
|
|
121
|
+
offset += 8;
|
|
122
|
+
const domain = readNullTerminatedString(page, startOffset + urlOffset);
|
|
123
|
+
const name = readNullTerminatedString(page, startOffset + nameOffset);
|
|
124
|
+
const cookiePath = readNullTerminatedString(page, startOffset + pathOffset);
|
|
125
|
+
const value = readNullTerminatedString(page, startOffset + valueOffset);
|
|
126
|
+
const secure = (flags & 1) !== 0;
|
|
127
|
+
const httpOnly = (flags & 4) !== 0;
|
|
128
|
+
return {
|
|
129
|
+
name,
|
|
130
|
+
value,
|
|
131
|
+
domain,
|
|
132
|
+
path: cookiePath,
|
|
133
|
+
expiry,
|
|
134
|
+
secure,
|
|
135
|
+
httpOnly
|
|
136
|
+
};
|
|
137
|
+
}
|
|
138
|
+
function readNullTerminatedString(buffer, offset) {
|
|
139
|
+
if (offset < 0 || offset >= buffer.length) {
|
|
140
|
+
return "";
|
|
141
|
+
}
|
|
142
|
+
const end = buffer.indexOf(0, offset);
|
|
143
|
+
if (end === -1) {
|
|
144
|
+
return buffer.subarray(offset).toString("utf8");
|
|
145
|
+
}
|
|
146
|
+
return buffer.subarray(offset, end).toString("utf8");
|
|
147
|
+
}
|
|
148
|
+
function filterAndConvertCookies(rawCookies, options, hosts, cookieNames) {
|
|
149
|
+
const cookies = [];
|
|
150
|
+
for (const raw of rawCookies) {
|
|
151
|
+
if (cookieNames && !cookieNames.has(raw.name)) {
|
|
152
|
+
continue;
|
|
153
|
+
}
|
|
154
|
+
const domain = raw.domain.startsWith(".") ? raw.domain.substring(1) : raw.domain;
|
|
155
|
+
const domainLower = domain.toLowerCase();
|
|
156
|
+
if (!hosts.some((h) => {
|
|
157
|
+
const hostLower = h.toLowerCase();
|
|
158
|
+
return hostLower === domainLower || hostLower.endsWith(`.${domainLower}`);
|
|
159
|
+
})) {
|
|
160
|
+
continue;
|
|
161
|
+
}
|
|
162
|
+
const expires = normalizeExpiration(raw.expiry, "safari");
|
|
163
|
+
if (!options.includeExpired && expires && expires < Date.now()) {
|
|
164
|
+
continue;
|
|
165
|
+
}
|
|
166
|
+
const cookie = {
|
|
167
|
+
name: raw.name,
|
|
168
|
+
value: raw.value,
|
|
169
|
+
domain,
|
|
170
|
+
path: raw.path || "/",
|
|
171
|
+
expires,
|
|
172
|
+
secure: raw.secure,
|
|
173
|
+
httpOnly: raw.httpOnly,
|
|
174
|
+
source: {
|
|
175
|
+
browser: "safari",
|
|
176
|
+
cookieFilePath: options.cookieFilePath
|
|
177
|
+
}
|
|
178
|
+
};
|
|
179
|
+
cookies.push(cookie);
|
|
180
|
+
}
|
|
181
|
+
return cookies;
|
|
182
|
+
}
|
|
183
|
+
function resolveSafariCookiePath(profile) {
|
|
184
|
+
profile = profile?.trim();
|
|
185
|
+
if (profile) {
|
|
186
|
+
const stat = statSync(profile, { throwIfNoEntry: false });
|
|
187
|
+
if (stat && stat.isFile()) {
|
|
188
|
+
return profile;
|
|
189
|
+
}
|
|
190
|
+
if (stat && stat.isDirectory()) {
|
|
191
|
+
const cookiePath = path.join(profile, "Cookies.binarycookies");
|
|
192
|
+
if (existsSync(cookiePath)) {
|
|
193
|
+
return cookiePath;
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
const homeDir = homedir();
|
|
198
|
+
const sandboxedPath = path.join(
|
|
199
|
+
homeDir,
|
|
200
|
+
"Library",
|
|
201
|
+
"Containers",
|
|
202
|
+
"com.apple.Safari",
|
|
203
|
+
"Data",
|
|
204
|
+
"Library",
|
|
205
|
+
"Cookies",
|
|
206
|
+
"Cookies.binarycookies"
|
|
207
|
+
);
|
|
208
|
+
if (existsSync(sandboxedPath)) {
|
|
209
|
+
return sandboxedPath;
|
|
210
|
+
}
|
|
211
|
+
const traditionalPath = path.join(homeDir, "Library", "Cookies", "Cookies.binarycookies");
|
|
212
|
+
if (existsSync(traditionalPath)) {
|
|
213
|
+
return traditionalPath;
|
|
214
|
+
}
|
|
215
|
+
return null;
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
export {
|
|
219
|
+
getCookiesFromSafari
|
|
220
|
+
};
|
|
221
|
+
//# sourceMappingURL=chunk-A3YGBITD.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/browsers/safariCookie.ts"],"sourcesContent":["import { homedir, tmpdir } from 'os';\nimport { copyFileSync, mkdtempSync, rmSync, existsSync, readFileSync, statSync } from 'fs';\nimport path from 'path';\nimport { GetCookiesOptions, GetCookiesResult, Cookie, GetCookiesFromFileOptions } from '../types';\nimport { normalizeExpiration } from '../common';\n\n/**\n * Safari BinaryCookies file format:\n * - Magic: \"cook\" (4 bytes)\n * - Number of pages: uint32 BE\n * - Page sizes: uint32 BE × numPages\n * - Pages data (concatenated)\n * - Checksum (8 bytes)\n *\n * Each page:\n * - Page header: 0x00000100 (4 bytes LE)\n * - Number of cookies: uint32 LE\n * - Cookie offsets: uint32 LE × numCookies\n * - Page end marker: 0x00000000 (4 bytes)\n * - Cookie records\n *\n * Each cookie record:\n * - Size: uint32 LE\n * - Flags: uint32 LE (bit 0 = secure, bit 2 = httpOnly)\n * - Unknown: 4 bytes\n * - URL offset: uint32 LE (relative to cookie start)\n * - Name offset: uint32 LE (relative to cookie start)\n * - Path offset: uint32 LE (relative to cookie start)\n * - Value offset: uint32 LE (relative to cookie start)\n * - Comment: 8 bytes\n * - Expiry date: float64 LE (CFAbsoluteTime, seconds since 2001-01-01)\n * - Creation date: float64 LE (CFAbsoluteTime)\n */\n\ninterface RawSafariCookie {\n name: string;\n value: string;\n domain: string;\n path: string;\n expiry: number;\n secure: boolean;\n httpOnly: boolean;\n}\n\nconst BINARY_COOKIES_MAGIC = 'cook';\n\n/**\n * Get cookies from Safari's Cookies.binarycookies file\n * @param options - Options for getting cookies\n * @param origins - List of origins to filter cookies by\n * @param cookieNames - Set of cookie names to filter (null for all)\n * @returns Promise resolving to cookies and warnings\n */\nexport async function getCookiesFromSafari(\n options: GetCookiesOptions,\n origins: string[],\n cookieNames: Set<string> | null\n): Promise<GetCookiesResult> {\n const warnings: string[] = [];\n\n if (process.platform !== 'darwin') {\n warnings.push('Safari cookies are only supported on macOS.');\n return { cookies: [], warnings };\n }\n\n // Parse hosts from origins\n let hosts: string[];\n try {\n hosts = origins.map((origin) => new URL(origin).hostname);\n } catch (error) {\n warnings.push(`Invalid URL: ${(error as Error).message}`);\n return { cookies: [], warnings };\n }\n\n const cookieFilePath = resolveSafariCookiePath(options.profile);\n if (!cookieFilePath) {\n warnings.push('Could not find Safari cookie file.');\n return { cookies: [], warnings };\n }\n\n // Copy the file to a temp location to avoid lock issues\n const tmpdirPath = mkdtempSync(path.join(tmpdir(), 'sqlite-cookie-safari-'));\n const tempFilePath = path.join(tmpdirPath, 'Cookies.binarycookies');\n try {\n copyFileSync(cookieFilePath, tempFilePath);\n } catch (error) {\n rmSync(tmpdirPath, { recursive: true, force: true });\n warnings.push(`Failed to copy Safari cookie file: ${(error as Error).message}`);\n return { cookies: [], warnings };\n }\n\n try {\n const fileBuffer = readFileSync(tempFilePath);\n const rawCookies = parseBinaryCookies(fileBuffer);\n const fileOptions: GetCookiesFromFileOptions = {\n cookieFilePath,\n profile: options.profile,\n includeExpired: options.includeExpired,\n };\n const cookies = filterAndConvertCookies(rawCookies, fileOptions, hosts, cookieNames);\n\n rmSync(tmpdirPath, { recursive: true, force: true });\n\n if (cookies.length === 0 && warnings.length === 0) {\n warnings.push('No cookies found.');\n }\n\n return { cookies, warnings };\n } catch (error) {\n rmSync(tmpdirPath, { recursive: true, force: true });\n warnings.push(`Failed to parse Safari cookie file: ${(error as Error).message}`);\n return { cookies: [], warnings };\n }\n}\n\n/**\n * Parse Safari's BinaryCookies file format\n */\nfunction parseBinaryCookies(buffer: Buffer): RawSafariCookie[] {\n let offset = 0;\n\n // Validate magic header\n const magic = buffer.subarray(0, 4).toString('ascii');\n if (magic !== BINARY_COOKIES_MAGIC) {\n throw new Error(\n `Invalid BinaryCookies magic: expected \"${BINARY_COOKIES_MAGIC}\", got \"${magic}\"`\n );\n }\n offset = 4;\n\n // Number of pages (big-endian)\n const numPages = buffer.readUInt32BE(offset);\n offset += 4;\n\n // Page sizes (big-endian)\n const pageSizes: number[] = [];\n for (let i = 0; i < numPages; i++) {\n pageSizes.push(buffer.readUInt32BE(offset));\n offset += 4;\n }\n\n // Parse each page\n const cookies: RawSafariCookie[] = [];\n for (let i = 0; i < numPages; i++) {\n const pageStart = offset;\n const pageBuffer = buffer.subarray(pageStart, pageStart + pageSizes[i]);\n const pageCookies = parsePage(pageBuffer);\n cookies.push(...pageCookies);\n offset += pageSizes[i];\n }\n\n return cookies;\n}\n\n/**\n * Parse a single page of cookies\n */\nfunction parsePage(page: Buffer): RawSafariCookie[] {\n let offset = 0;\n\n // Page header (0x00000100, little-endian)\n // const pageHeader = page.readUInt32LE(offset);\n offset += 4;\n\n // Number of cookies in this page\n const numCookies = page.readUInt32LE(offset);\n offset += 4;\n\n // Cookie offsets (relative to page start)\n const cookieOffsets: number[] = [];\n for (let i = 0; i < numCookies; i++) {\n cookieOffsets.push(page.readUInt32LE(offset));\n offset += 4;\n }\n\n // Parse each cookie\n const cookies: RawSafariCookie[] = [];\n for (const cookieOffset of cookieOffsets) {\n try {\n const cookie = parseCookieRecord(page, cookieOffset);\n if (cookie) {\n cookies.push(cookie);\n }\n } catch {\n // Skip malformed cookie records\n }\n }\n\n return cookies;\n}\n\n/**\n * Parse a single cookie record from the page buffer\n */\nfunction parseCookieRecord(page: Buffer, startOffset: number): RawSafariCookie | null {\n let offset = startOffset;\n\n // Cookie size\n // const cookieSize = page.readUInt32LE(offset);\n offset += 4;\n\n // Flags (bit 0 = secure, bit 2 = httpOnly)\n const flags = page.readUInt32LE(offset);\n offset += 4;\n\n // Unknown fields (2 × 4 bytes)\n offset += 8;\n\n // String offsets (relative to cookie start)\n const urlOffset = page.readUInt32LE(offset);\n offset += 4;\n const nameOffset = page.readUInt32LE(offset);\n offset += 4;\n const pathOffset = page.readUInt32LE(offset);\n offset += 4;\n const valueOffset = page.readUInt32LE(offset);\n offset += 4;\n\n // Comment/unknown (8 bytes, skip)\n offset += 8;\n\n // Expiry date (CFAbsoluteTime, float64 LE)\n const expiry = page.readDoubleLE(offset);\n offset += 8;\n\n // Creation date (skip)\n // offset += 8;\n\n // Read null-terminated strings\n const domain = readNullTerminatedString(page, startOffset + urlOffset);\n const name = readNullTerminatedString(page, startOffset + nameOffset);\n const cookiePath = readNullTerminatedString(page, startOffset + pathOffset);\n const value = readNullTerminatedString(page, startOffset + valueOffset);\n\n const secure = (flags & 0x1) !== 0;\n const httpOnly = (flags & 0x4) !== 0;\n\n return {\n name,\n value,\n domain,\n path: cookiePath,\n expiry,\n secure,\n httpOnly,\n };\n}\n\n/**\n * Read a null-terminated string from a buffer\n */\nfunction readNullTerminatedString(buffer: Buffer, offset: number): string {\n if (offset < 0 || offset >= buffer.length) {\n return '';\n }\n const end = buffer.indexOf(0, offset);\n if (end === -1) {\n return buffer.subarray(offset).toString('utf8');\n }\n return buffer.subarray(offset, end).toString('utf8');\n}\n\n/**\n * Filter raw Safari cookies by host, name, and expiry, then convert to Cookie objects\n */\nfunction filterAndConvertCookies(\n rawCookies: RawSafariCookie[],\n options: GetCookiesFromFileOptions,\n hosts: string[],\n cookieNames: Set<string> | null\n): Cookie[] {\n const cookies: Cookie[] = [];\n\n for (const raw of rawCookies) {\n // Filter by cookie name\n if (cookieNames && !cookieNames.has(raw.name)) {\n continue;\n }\n\n // Normalize domain (remove leading dot)\n const domain = raw.domain.startsWith('.') ? raw.domain.substring(1) : raw.domain;\n const domainLower = domain.toLowerCase();\n\n // Check if this cookie matches any of the requested hosts\n if (\n !hosts.some((h) => {\n const hostLower = h.toLowerCase();\n return hostLower === domainLower || hostLower.endsWith(`.${domainLower}`);\n })\n ) {\n continue;\n }\n\n // Convert expiry (CFAbsoluteTime -> JS milliseconds)\n const expires = normalizeExpiration(raw.expiry, 'safari');\n\n // Filter expired cookies\n if (!options.includeExpired && expires && expires < Date.now()) {\n continue;\n }\n\n const cookie: Cookie = {\n name: raw.name,\n value: raw.value,\n domain,\n path: raw.path || '/',\n expires,\n secure: raw.secure,\n httpOnly: raw.httpOnly,\n source: {\n browser: 'safari',\n cookieFilePath: options.cookieFilePath,\n },\n };\n\n cookies.push(cookie);\n }\n\n return cookies;\n}\n\n/**\n * Resolve the path to Safari's Cookies.binarycookies file\n *\n * Safari cookie file locations on macOS:\n * - ~/Library/Cookies/Cookies.binarycookies (traditional)\n * - ~/Library/Containers/com.apple.Safari/Data/Library/Cookies/Cookies.binarycookies (sandboxed)\n */\nfunction resolveSafariCookiePath(profile?: string): string | null {\n profile = profile?.trim();\n // If profile is a direct file path\n if (profile) {\n const stat = statSync(profile, { throwIfNoEntry: false });\n if (stat && stat.isFile()) {\n return profile;\n }\n // Could be a directory containing the cookie file\n if (stat && stat.isDirectory()) {\n const cookiePath = path.join(profile, 'Cookies.binarycookies');\n if (existsSync(cookiePath)) {\n return cookiePath;\n }\n }\n }\n\n const homeDir = homedir();\n\n // Try sandboxed location first (newer macOS)\n const sandboxedPath = path.join(\n homeDir,\n 'Library',\n 'Containers',\n 'com.apple.Safari',\n 'Data',\n 'Library',\n 'Cookies',\n 'Cookies.binarycookies'\n );\n if (existsSync(sandboxedPath)) {\n return sandboxedPath;\n }\n\n // Traditional location\n const traditionalPath = path.join(homeDir, 'Library', 'Cookies', 'Cookies.binarycookies');\n if (existsSync(traditionalPath)) {\n return traditionalPath;\n }\n\n return null;\n}\n"],"mappings":"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","names":[]}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import {
|
|
2
|
+
executeProcess
|
|
3
|
+
} from "./chunk-LTLRZZW3.js";
|
|
4
|
+
|
|
5
|
+
// src/util/windowsDpapi.ts
|
|
6
|
+
async function decryptWindowsDpapi(encryptedBytes, timeoutMs = 5e3) {
|
|
7
|
+
const base64Input = encryptedBytes.toString("base64");
|
|
8
|
+
const script = [
|
|
9
|
+
"Add-Type -AssemblyName System.Security",
|
|
10
|
+
`$bytes = [Convert]::FromBase64String("${base64Input}")`,
|
|
11
|
+
"$decrypted = [System.Security.Cryptography.ProtectedData]::Unprotect($bytes, $null, [System.Security.Cryptography.DataProtectionScope]::CurrentUser)",
|
|
12
|
+
"[Convert]::ToBase64String($decrypted)"
|
|
13
|
+
].join("; ");
|
|
14
|
+
const result = await executeProcess(
|
|
15
|
+
"powershell.exe",
|
|
16
|
+
["-NoProfile", "-NonInteractive", "-Command", script],
|
|
17
|
+
timeoutMs
|
|
18
|
+
);
|
|
19
|
+
if (result.code !== 0) {
|
|
20
|
+
return { success: false, error: result.stderr.trim() || `powershell exit ${result.code}` };
|
|
21
|
+
}
|
|
22
|
+
const output = result.stdout.trim();
|
|
23
|
+
if (!output) {
|
|
24
|
+
return { success: false, error: "DPAPI decryption returned empty result" };
|
|
25
|
+
}
|
|
26
|
+
try {
|
|
27
|
+
const decrypted = Buffer.from(output, "base64");
|
|
28
|
+
return { success: true, decrypted };
|
|
29
|
+
} catch (error) {
|
|
30
|
+
return { success: false, error: `Failed to decode DPAPI result: ${error.message}` };
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export {
|
|
35
|
+
decryptWindowsDpapi
|
|
36
|
+
};
|
|
37
|
+
//# sourceMappingURL=chunk-AR5Q6KM4.js.map
|