@mherod/get-cookie 2.0.0-beta.9 → 2.0.0-rc.10
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/.github/dependabot.yml +6 -0
- package/dist/index.js +459 -174
- package/package-lock.json +12295 -0
- package/package.json +16 -9
- package/src/CookieRow.ts +2 -1
- package/src/CookieSpec.ts +4 -0
- package/src/CookieStore.ts +10 -0
- package/src/ExportedCookie.ts +2 -1
- package/src/{fetchResponse.ts → FetchResponse.ts} +5 -1
- package/src/IsCookieRow.ts +6 -2
- package/src/IsExportedCookie.ts +6 -2
- package/src/SpecialCases.ts +14 -0
- package/src/StringToRegex.ts +6 -0
- package/src/argv.ts +4 -0
- package/src/browsers/ChromeCookieQueryStrategy.ts +190 -106
- package/src/browsers/CompositeCookieQueryStrategy.ts +49 -7
- package/src/browsers/CookieQueryStrategy.ts +3 -2
- package/src/browsers/CookieStoreQueryStrategy.ts +94 -0
- package/src/browsers/FirefoxCookieQueryStrategy.ts +54 -46
- package/src/browsers/SafariCookieQueryStrategy.ts +3 -1
- package/src/cli.ts +90 -61
- package/src/doSqliteQuery1.ts +17 -11
- package/src/doSqliteQuery1Params.ts +7 -0
- package/src/fetchWithCookies.ts +84 -31
- package/src/findAllFiles.ts +16 -22
- package/src/getChromeCookie.ts +19 -0
- package/src/getCookie.ts +19 -0
- package/src/getFirefoxCookie.ts +19 -0
- package/src/getGroupedRenderedCookies.ts +19 -22
- package/src/getMergedRenderedCookies.ts +25 -0
- package/src/global.ts +2 -1
- package/src/index.ts +10 -46
- package/src/isValidJwt.ts +13 -3
- package/src/queryCookies.ts +17 -16
- package/src/resultsRendered.ts +7 -4
- package/src/unpackHeaders.ts +16 -0
- package/src/utils.ts +1 -32
- package/dist/cli.js +0 -3
- package/dist/cli.js.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/module.js +0 -533
- package/dist/module.js.map +0 -1
- package/dist/types.d.ts +0 -35
- package/dist/types.d.ts.map +0 -1
- package/src/CookieRequest.ts +0 -4
package/package.json
CHANGED
|
@@ -1,21 +1,23 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mherod/get-cookie",
|
|
3
|
-
"version": "2.0.0-
|
|
3
|
+
"version": "2.0.0-rc.10",
|
|
4
4
|
"description": "Node.js module for querying a local user's Chrome cookie",
|
|
5
5
|
"source": "src/index.ts",
|
|
6
6
|
"bin": "dist/cli.js",
|
|
7
|
-
"main": "dist/
|
|
7
|
+
"main": "dist/index.js",
|
|
8
8
|
"module": "dist/module.js",
|
|
9
9
|
"types": "dist/types.d.ts",
|
|
10
10
|
"publishConfig": {
|
|
11
11
|
"access": "public"
|
|
12
12
|
},
|
|
13
13
|
"scripts": {
|
|
14
|
-
"clean": "git clean -
|
|
14
|
+
"clean": "git clean -fdX && rm -rf node_modules dist && yarn install",
|
|
15
15
|
"build": "parcel build",
|
|
16
|
+
"prepare": "npm run build && npm run prettier",
|
|
16
17
|
"test": "jest",
|
|
17
|
-
"postbuild": "npm run check
|
|
18
|
+
"postbuild": "npm run check",
|
|
18
19
|
"prepublish": "npm run build",
|
|
20
|
+
"preinstall:global": "npm run build",
|
|
19
21
|
"install:global": "npm install --force --global .",
|
|
20
22
|
"postinstall:global": "find $NVM_BIN -exec chmod +x {} \\; || true",
|
|
21
23
|
"prettier": "prettier --write 'src/{**/*,*}.{js,json,ts}'",
|
|
@@ -25,14 +27,13 @@
|
|
|
25
27
|
"main": {},
|
|
26
28
|
"types": {},
|
|
27
29
|
"library": {
|
|
28
|
-
"source":
|
|
29
|
-
"src/index.ts"
|
|
30
|
-
],
|
|
30
|
+
"source": "src/index.ts",
|
|
31
31
|
"distDir": "dist",
|
|
32
32
|
"isLibrary": true,
|
|
33
33
|
"engines": {
|
|
34
34
|
"node": "16"
|
|
35
|
-
}
|
|
35
|
+
},
|
|
36
|
+
"includeNodeModules": false
|
|
36
37
|
},
|
|
37
38
|
"cli": {
|
|
38
39
|
"source": "src/cli.ts",
|
|
@@ -62,15 +63,21 @@
|
|
|
62
63
|
"destr": "^1.1.1",
|
|
63
64
|
"jsonwebtoken": "^8.5.1",
|
|
64
65
|
"lodash": "^4.17.21",
|
|
66
|
+
"lru-cache": "^7.14.0",
|
|
67
|
+
"minimist": "^1.2.6",
|
|
65
68
|
"sqlite3": "^5.1.1",
|
|
66
|
-
"
|
|
69
|
+
"tough-cookie": "^4.1.2",
|
|
70
|
+
"tough-cookie-file-store": "^2.0.3",
|
|
71
|
+
"user-agents": "^1.0.1165"
|
|
67
72
|
},
|
|
68
73
|
"devDependencies": {
|
|
69
74
|
"@parcel/packager-ts": "^2.7.0",
|
|
70
75
|
"@parcel/transformer-typescript-types": "^2.7.0",
|
|
71
76
|
"@types/jsonwebtoken": "^8.5.9",
|
|
72
77
|
"@types/lodash": "^4.14.186",
|
|
78
|
+
"@types/minimist": "^1.2.2",
|
|
73
79
|
"@types/node": "^18.8.2",
|
|
80
|
+
"@types/tough-cookie": "^4.0.2",
|
|
74
81
|
"@types/user-agents": "^1.0.2",
|
|
75
82
|
"jest": "^29.0.3",
|
|
76
83
|
"parcel": "^2.7.0",
|
package/src/CookieRow.ts
CHANGED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { CookieJar } from "tough-cookie";
|
|
2
|
+
import { env } from "./global";
|
|
3
|
+
const { FileCookieStore } = require("tough-cookie-file-store");
|
|
4
|
+
|
|
5
|
+
export const cookieStore = new FileCookieStore(
|
|
6
|
+
`${env["HOME"]}/cookie-star.json`
|
|
7
|
+
);
|
|
8
|
+
// export const cookieStore = new MemoryCookieStore();
|
|
9
|
+
|
|
10
|
+
export const cookieJar = new CookieJar(cookieStore);
|
package/src/ExportedCookie.ts
CHANGED
package/src/IsCookieRow.ts
CHANGED
|
@@ -1,5 +1,9 @@
|
|
|
1
|
-
import
|
|
1
|
+
import CookieRow from "./CookieRow";
|
|
2
2
|
|
|
3
3
|
export function isCookieRow(obj: any): obj is CookieRow {
|
|
4
|
-
return
|
|
4
|
+
return (
|
|
5
|
+
obj.domain !== undefined &&
|
|
6
|
+
obj.name !== undefined &&
|
|
7
|
+
obj.value !== undefined
|
|
8
|
+
);
|
|
5
9
|
}
|
package/src/IsExportedCookie.ts
CHANGED
|
@@ -1,5 +1,9 @@
|
|
|
1
|
-
import
|
|
1
|
+
import ExportedCookie from "./ExportedCookie";
|
|
2
2
|
|
|
3
3
|
export function isExportedCookie(obj: any): obj is ExportedCookie {
|
|
4
|
-
return
|
|
4
|
+
return (
|
|
5
|
+
obj.domain !== undefined &&
|
|
6
|
+
obj.name !== undefined &&
|
|
7
|
+
obj.value !== undefined
|
|
8
|
+
);
|
|
5
9
|
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import CookieSpec from "./CookieSpec";
|
|
2
|
+
|
|
3
|
+
export function specialCases({ name, domain }: CookieSpec): {
|
|
4
|
+
specifiedName: boolean;
|
|
5
|
+
specifiedDomain: boolean;
|
|
6
|
+
//
|
|
7
|
+
} {
|
|
8
|
+
const wildcardRegexp = /^([*%])$/i;
|
|
9
|
+
return {
|
|
10
|
+
specifiedName: name.match(wildcardRegexp) == null,
|
|
11
|
+
specifiedDomain: domain.match(wildcardRegexp) == null,
|
|
12
|
+
//
|
|
13
|
+
};
|
|
14
|
+
}
|
package/src/argv.ts
CHANGED
|
@@ -9,10 +9,17 @@ import { doSqliteQuery1 } from "../doSqliteQuery1";
|
|
|
9
9
|
import { merge } from "lodash";
|
|
10
10
|
import { isCookieRow } from "../IsCookieRow";
|
|
11
11
|
import { isExportedCookie } from "../IsExportedCookie";
|
|
12
|
-
import
|
|
13
|
-
import
|
|
12
|
+
import CookieRow from "../CookieRow";
|
|
13
|
+
import ExportedCookie from "../ExportedCookie";
|
|
14
|
+
import { stringToRegex } from "../StringToRegex";
|
|
15
|
+
import { parsedArgs } from "../argv";
|
|
16
|
+
import fs from "fs";
|
|
17
|
+
import * as sqlite3 from "sqlite3";
|
|
18
|
+
import { DoSqliteQuery1Params } from "../doSqliteQuery1Params";
|
|
14
19
|
|
|
15
20
|
export default class ChromeCookieQueryStrategy implements CookieQueryStrategy {
|
|
21
|
+
browserName = "Chrome";
|
|
22
|
+
|
|
16
23
|
async queryCookies(name: string, domain: string): Promise<ExportedCookie[]> {
|
|
17
24
|
if (process.platform !== "darwin") {
|
|
18
25
|
throw new Error("This only works on macOS");
|
|
@@ -23,20 +30,24 @@ export default class ChromeCookieQueryStrategy implements CookieQueryStrategy {
|
|
|
23
30
|
return getChromeCookies({
|
|
24
31
|
requireJwt: false,
|
|
25
32
|
name,
|
|
26
|
-
domain
|
|
33
|
+
domain,
|
|
27
34
|
});
|
|
28
35
|
}
|
|
29
36
|
}
|
|
30
37
|
|
|
31
|
-
async function getPromise1(
|
|
38
|
+
async function getPromise1(
|
|
39
|
+
name: string,
|
|
40
|
+
domain: string,
|
|
41
|
+
file: string
|
|
42
|
+
): Promise<CookieRow[]> {
|
|
32
43
|
try {
|
|
33
44
|
return await getEncryptedChromeCookie({
|
|
34
45
|
name: name,
|
|
35
46
|
domain: domain,
|
|
36
|
-
file: file
|
|
47
|
+
file: file,
|
|
37
48
|
});
|
|
38
49
|
} catch (e) {
|
|
39
|
-
if (
|
|
50
|
+
if (parsedArgs.verbose) {
|
|
40
51
|
console.log("Error getting encrypted cookie", e);
|
|
41
52
|
}
|
|
42
53
|
return [];
|
|
@@ -47,13 +58,15 @@ async function getPromise(name: string, domain: string): Promise<CookieRow[]> {
|
|
|
47
58
|
try {
|
|
48
59
|
const files: string[] = await findAllFiles({
|
|
49
60
|
path: chromeLocal,
|
|
50
|
-
name: "Cookies"
|
|
61
|
+
name: "Cookies",
|
|
51
62
|
});
|
|
52
|
-
const promises: Promise<CookieRow[]>[] = files.map((file) =>
|
|
53
|
-
|
|
63
|
+
const promises: Promise<CookieRow[]>[] = files.map((file) =>
|
|
64
|
+
getPromise1(name, domain, file)
|
|
65
|
+
);
|
|
66
|
+
const results1: CookieRow[][] = await Promise.all(promises);
|
|
54
67
|
return results1.flat().filter(isCookieRow);
|
|
55
68
|
} catch (error) {
|
|
56
|
-
if (
|
|
69
|
+
if (parsedArgs.verbose) {
|
|
57
70
|
console.log("error", error);
|
|
58
71
|
}
|
|
59
72
|
return [];
|
|
@@ -65,7 +78,7 @@ async function decryptValue(password: string, encryptedValue: Buffer) {
|
|
|
65
78
|
try {
|
|
66
79
|
d = await decrypt(password, encryptedValue);
|
|
67
80
|
} catch (e) {
|
|
68
|
-
if (
|
|
81
|
+
if (parsedArgs.verbose) {
|
|
69
82
|
console.log("Error decrypting cookie", e);
|
|
70
83
|
}
|
|
71
84
|
d = null;
|
|
@@ -73,19 +86,17 @@ async function decryptValue(password: string, encryptedValue: Buffer) {
|
|
|
73
86
|
return d ?? encryptedValue.toString("utf-8");
|
|
74
87
|
}
|
|
75
88
|
|
|
76
|
-
async function getChromeCookies(
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
requireJwt: boolean | undefined;
|
|
85
|
-
//
|
|
86
|
-
}
|
|
89
|
+
async function getChromeCookies({
|
|
90
|
+
name,
|
|
91
|
+
domain = "%",
|
|
92
|
+
requireJwt = false,
|
|
93
|
+
}: {
|
|
94
|
+
name: string;
|
|
95
|
+
domain: string;
|
|
96
|
+
requireJwt: boolean | undefined;
|
|
87
97
|
//
|
|
88
|
-
):
|
|
98
|
+
}): //
|
|
99
|
+
Promise<ExportedCookie[]> {
|
|
89
100
|
const encryptedDataItems: CookieRow[] = await getPromise(name, domain);
|
|
90
101
|
const password: string = await getChromePassword();
|
|
91
102
|
const decrypted: Promise<ExportedCookie | null>[] = encryptedDataItems
|
|
@@ -95,15 +106,24 @@ async function getChromeCookies(
|
|
|
95
106
|
const decryptedValue = await decryptValue(password, encryptedValue);
|
|
96
107
|
const meta = {};
|
|
97
108
|
merge(meta, cookieRow.meta ?? {});
|
|
98
|
-
|
|
109
|
+
const exportedCookie: ExportedCookie = {
|
|
99
110
|
domain: cookieRow.domain,
|
|
100
111
|
name: cookieRow.name,
|
|
101
112
|
value: decryptedValue,
|
|
102
|
-
meta: meta
|
|
113
|
+
meta: meta,
|
|
103
114
|
};
|
|
115
|
+
const expiry = cookieRow.expiry;
|
|
116
|
+
if (expiry) {
|
|
117
|
+
merge(exportedCookie, {
|
|
118
|
+
expiry: new Date(expiry),
|
|
119
|
+
});
|
|
120
|
+
}
|
|
121
|
+
return exportedCookie;
|
|
104
122
|
});
|
|
105
|
-
const results: ExportedCookie[] = (await Promise.all(decrypted)).filter(
|
|
106
|
-
|
|
123
|
+
const results: ExportedCookie[] = (await Promise.all(decrypted)).filter(
|
|
124
|
+
isExportedCookie
|
|
125
|
+
);
|
|
126
|
+
if (parsedArgs.verbose) {
|
|
107
127
|
console.log("results", results);
|
|
108
128
|
}
|
|
109
129
|
return results;
|
|
@@ -117,51 +137,79 @@ const chromeLocal = path.join(
|
|
|
117
137
|
"Chrome"
|
|
118
138
|
);
|
|
119
139
|
|
|
120
|
-
async function getEncryptedChromeCookie(
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
}): Promise<CookieRow[]> {
|
|
140
|
+
async function getEncryptedChromeCookie({
|
|
141
|
+
name,
|
|
142
|
+
domain,
|
|
143
|
+
file = path.join(chromeLocal, "Default", "Cookies"),
|
|
144
|
+
}: //
|
|
145
|
+
{
|
|
146
|
+
name: string;
|
|
147
|
+
domain: string;
|
|
148
|
+
file: string;
|
|
149
|
+
}): Promise<CookieRow[]> {
|
|
131
150
|
if (!existsSync(file)) {
|
|
132
151
|
throw new Error(`File ${file} does not exist`);
|
|
133
152
|
}
|
|
134
|
-
if (
|
|
153
|
+
if (parsedArgs.verbose) {
|
|
135
154
|
const s = file.split("/").slice(-3).join("/");
|
|
136
155
|
console.log(`Trying Chrome (at ${s}) cookie ${name} for domain ${domain}`);
|
|
137
156
|
}
|
|
138
157
|
let sql;
|
|
139
|
-
|
|
158
|
+
//language=SQL
|
|
159
|
+
sql = "SELECT * FROM cookies";
|
|
160
|
+
// sql = "SELECT encrypted_value, name, host_key FROM cookies";
|
|
161
|
+
|
|
140
162
|
const wildcardRegexp = /^([*%])$/i;
|
|
141
163
|
const specifiedName = name.match(wildcardRegexp) == null;
|
|
142
164
|
const specifiedDomain = domain.match(wildcardRegexp) == null;
|
|
143
|
-
|
|
165
|
+
const wildcardDomain = domain.match(/[%*]/) != null;
|
|
166
|
+
const queryDomain = specifiedDomain && !wildcardDomain;
|
|
167
|
+
// if we have a wildcard domain, we need to use a regexp
|
|
168
|
+
if (specifiedName || queryDomain) {
|
|
144
169
|
sql += ` WHERE `;
|
|
145
170
|
if (specifiedName) {
|
|
146
171
|
sql += `name = '${name}'`;
|
|
147
|
-
if (
|
|
172
|
+
if (queryDomain) {
|
|
148
173
|
sql += ` AND `;
|
|
149
174
|
}
|
|
150
175
|
}
|
|
151
|
-
if (
|
|
152
|
-
|
|
176
|
+
if (queryDomain) {
|
|
177
|
+
// leading dot replaced with % to match subdomains
|
|
178
|
+
const sqlEmbedDomain = domain.replace(/^[.%]?/, "%");
|
|
179
|
+
sql += `host_key LIKE '${sqlEmbedDomain}';`;
|
|
153
180
|
}
|
|
154
181
|
}
|
|
155
|
-
|
|
182
|
+
const sqliteQuery1: CookieRow[] = await doChromeSqliteQuery1({
|
|
183
|
+
file: file,
|
|
184
|
+
sql: sql,
|
|
185
|
+
rowTransform: (row) => {
|
|
186
|
+
const cookieRow = {
|
|
187
|
+
expiry: (row["expires_utc"] / 1000000 - 11644473600) * 1000,
|
|
188
|
+
domain: row["host_key"],
|
|
189
|
+
name: row["name"],
|
|
190
|
+
value: row["encrypted_value"],
|
|
191
|
+
};
|
|
192
|
+
if (parsedArgs.verbose) {
|
|
193
|
+
console.log("CookieRow", cookieRow);
|
|
194
|
+
}
|
|
195
|
+
return cookieRow;
|
|
196
|
+
},
|
|
197
|
+
});
|
|
198
|
+
return sqliteQuery1.filter((row) => {
|
|
199
|
+
return row.domain.match(stringToRegex(domain)) != null;
|
|
200
|
+
});
|
|
156
201
|
}
|
|
157
202
|
|
|
158
203
|
async function getChromePassword(): Promise<string> {
|
|
159
204
|
return execSimple(
|
|
160
|
-
|
|
205
|
+
'security find-generic-password -w -s "Chrome Safe Storage"'
|
|
161
206
|
);
|
|
162
207
|
}
|
|
163
208
|
|
|
164
|
-
async function decrypt(
|
|
209
|
+
async function decrypt(
|
|
210
|
+
password: crypto.BinaryLike,
|
|
211
|
+
encryptedData: Buffer
|
|
212
|
+
): Promise<string> {
|
|
165
213
|
if (typeof password !== "string") {
|
|
166
214
|
throw new Error("password must be a string: " + password);
|
|
167
215
|
}
|
|
@@ -173,7 +221,7 @@ async function decrypt(password: crypto.BinaryLike, encryptedData: Buffer): Prom
|
|
|
173
221
|
if (!(encryptedData1 instanceof Buffer)) {
|
|
174
222
|
if (Array.isArray(encryptedData1) && encryptedData1[0] instanceof Buffer) {
|
|
175
223
|
[encryptedData1] = encryptedData1;
|
|
176
|
-
if (
|
|
224
|
+
if (parsedArgs.verbose) {
|
|
177
225
|
console.log(
|
|
178
226
|
`encryptedData is an array of buffers, selected first: ${encryptedData1}`
|
|
179
227
|
);
|
|
@@ -183,77 +231,113 @@ async function decrypt(password: crypto.BinaryLike, encryptedData: Buffer): Prom
|
|
|
183
231
|
}
|
|
184
232
|
encryptedData1 = Buffer.from(encryptedData1);
|
|
185
233
|
}
|
|
186
|
-
if (
|
|
234
|
+
if (parsedArgs.verbose) {
|
|
187
235
|
console.log(`Trying to decrypt with password ${password}`);
|
|
188
236
|
}
|
|
189
237
|
return new Promise((resolve, reject) => {
|
|
190
|
-
crypto.pbkdf2(password,
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
(error, buffer) => {
|
|
196
|
-
try {
|
|
197
|
-
if (error) {
|
|
198
|
-
if (env.VERBOSE) {
|
|
199
|
-
console.log("Error doing pbkdf2", error);
|
|
200
|
-
}
|
|
201
|
-
reject(error);
|
|
202
|
-
return;
|
|
238
|
+
crypto.pbkdf2(password, "saltysalt", 1003, 16, "sha1", (error, buffer) => {
|
|
239
|
+
try {
|
|
240
|
+
if (error) {
|
|
241
|
+
if (parsedArgs.verbose) {
|
|
242
|
+
console.log("Error doing pbkdf2", error);
|
|
203
243
|
}
|
|
244
|
+
reject(error);
|
|
245
|
+
return;
|
|
246
|
+
}
|
|
204
247
|
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
}
|
|
212
|
-
reject(new Error("Buffer length is not 16"));
|
|
213
|
-
return;
|
|
248
|
+
if (buffer.length !== 16) {
|
|
249
|
+
if (parsedArgs.verbose) {
|
|
250
|
+
console.log(
|
|
251
|
+
"Error doing pbkdf2, buffer length is not 16",
|
|
252
|
+
buffer.length
|
|
253
|
+
);
|
|
214
254
|
}
|
|
255
|
+
reject(new Error("Buffer length is not 16"));
|
|
256
|
+
return;
|
|
257
|
+
}
|
|
215
258
|
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
if (encryptedData1 && encryptedData1.slice) {
|
|
222
|
-
encryptedData1 = encryptedData1.slice(3);
|
|
223
|
-
}
|
|
259
|
+
const str = new Array(17).join(" ");
|
|
260
|
+
const iv = Buffer.from(str, "binary");
|
|
261
|
+
const decipher = crypto.createDecipheriv("aes-128-cbc", buffer, iv);
|
|
262
|
+
decipher.setAutoPadding(false);
|
|
224
263
|
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
"Error doing pbkdf2, encryptedData length is not a multiple of 16",
|
|
229
|
-
encryptedData1.length
|
|
230
|
-
);
|
|
231
|
-
}
|
|
232
|
-
reject(new Error("encryptedData length is not a multiple of 16"));
|
|
233
|
-
return;
|
|
234
|
-
}
|
|
264
|
+
if (encryptedData1 && encryptedData1.slice) {
|
|
265
|
+
encryptedData1 = encryptedData1.slice(3);
|
|
266
|
+
}
|
|
235
267
|
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
}
|
|
243
|
-
reject(e);
|
|
244
|
-
return;
|
|
268
|
+
if (encryptedData1.length % 16 !== 0) {
|
|
269
|
+
if (parsedArgs.verbose) {
|
|
270
|
+
console.log(
|
|
271
|
+
"Error doing pbkdf2, encryptedData length is not a multiple of 16",
|
|
272
|
+
encryptedData1.length
|
|
273
|
+
);
|
|
245
274
|
}
|
|
275
|
+
reject(new Error("encryptedData length is not a multiple of 16"));
|
|
276
|
+
return;
|
|
277
|
+
}
|
|
246
278
|
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
}
|
|
251
|
-
// noinspection JSCheckFunctionSignatures
|
|
252
|
-
const decodedString = decoded.toString("utf8");
|
|
253
|
-
resolve(decodedString);
|
|
279
|
+
let decoded = decipher.update(encryptedData1);
|
|
280
|
+
try {
|
|
281
|
+
decipher.final("utf-8");
|
|
254
282
|
} catch (e) {
|
|
283
|
+
if (parsedArgs.verbose) {
|
|
284
|
+
console.log("Error doing decipher.final()", e);
|
|
285
|
+
}
|
|
255
286
|
reject(e);
|
|
287
|
+
return;
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
const padding = decoded[decoded.length - 1];
|
|
291
|
+
if (padding) {
|
|
292
|
+
decoded = decoded.slice(0, 0 - padding);
|
|
256
293
|
}
|
|
257
|
-
|
|
294
|
+
// noinspection JSCheckFunctionSignatures
|
|
295
|
+
const decodedString = decoded.toString("utf8");
|
|
296
|
+
resolve(decodedString);
|
|
297
|
+
} catch (e) {
|
|
298
|
+
reject(e);
|
|
299
|
+
}
|
|
300
|
+
});
|
|
301
|
+
});
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
export async function doChromeSqliteQuery1({
|
|
305
|
+
file,
|
|
306
|
+
sql,
|
|
307
|
+
rowTransform,
|
|
308
|
+
}: DoSqliteQuery1Params): Promise<CookieRow[]> {
|
|
309
|
+
if (!file || (file && !fs.existsSync(file))) {
|
|
310
|
+
throw new Error(`doSqliteQuery1: file ${file} does not exist`);
|
|
311
|
+
}
|
|
312
|
+
const db = new sqlite3.Database(file);
|
|
313
|
+
return new Promise((resolve, reject) => {
|
|
314
|
+
db.all(sql, (err: Error, rows: any[]) => {
|
|
315
|
+
if (err) {
|
|
316
|
+
reject(err);
|
|
317
|
+
return;
|
|
318
|
+
}
|
|
319
|
+
const rows1: any[] = rows;
|
|
320
|
+
if (rows1 == null || rows1.length === 0) {
|
|
321
|
+
resolve([]);
|
|
322
|
+
return;
|
|
323
|
+
}
|
|
324
|
+
if (Array.isArray(rows1)) {
|
|
325
|
+
const cookieRows: CookieRow[] = rows1.map((row: any) => {
|
|
326
|
+
const newVar = {
|
|
327
|
+
meta: {
|
|
328
|
+
file: file,
|
|
329
|
+
},
|
|
330
|
+
};
|
|
331
|
+
const cookieRow: CookieRow = rowTransform(row);
|
|
332
|
+
return merge(newVar, cookieRow);
|
|
333
|
+
});
|
|
334
|
+
resolve(cookieRows);
|
|
335
|
+
return;
|
|
336
|
+
}
|
|
337
|
+
if (parsedArgs.verbose) {
|
|
338
|
+
console.log(`doSqliteQuery1: rows ${JSON.stringify(rows1)}`);
|
|
339
|
+
}
|
|
340
|
+
resolve([rows1]);
|
|
341
|
+
});
|
|
258
342
|
});
|
|
259
343
|
}
|
|
@@ -2,13 +2,28 @@ import ChromeCookieQueryStrategy from "./ChromeCookieQueryStrategy";
|
|
|
2
2
|
import FirefoxCookieQueryStrategy from "./FirefoxCookieQueryStrategy";
|
|
3
3
|
import SafariCookieQueryStrategy from "./SafariCookieQueryStrategy";
|
|
4
4
|
import CookieQueryStrategy from "./CookieQueryStrategy";
|
|
5
|
-
import
|
|
5
|
+
import ExportedCookie from "../ExportedCookie";
|
|
6
|
+
import LRUCache from "lru-cache";
|
|
7
|
+
import CookieStoreQueryStrategy from "./CookieStoreQueryStrategy";
|
|
8
|
+
import { red } from "colorette";
|
|
9
|
+
import { merge } from "lodash";
|
|
10
|
+
import { parsedArgs } from "../argv";
|
|
11
|
+
|
|
12
|
+
const cache = new LRUCache<string, ExportedCookie[]>({
|
|
13
|
+
ttl: 1000 * 2,
|
|
14
|
+
max: 10,
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
export default class CompositeCookieQueryStrategy
|
|
18
|
+
implements CookieQueryStrategy
|
|
19
|
+
{
|
|
20
|
+
browserName = "all";
|
|
6
21
|
|
|
7
|
-
export default class CompositeCookieQueryStrategy implements CookieQueryStrategy {
|
|
8
22
|
#strategies;
|
|
9
23
|
|
|
10
24
|
constructor() {
|
|
11
25
|
this.#strategies = [
|
|
26
|
+
CookieStoreQueryStrategy,
|
|
12
27
|
ChromeCookieQueryStrategy,
|
|
13
28
|
FirefoxCookieQueryStrategy,
|
|
14
29
|
SafariCookieQueryStrategy,
|
|
@@ -18,13 +33,40 @@ export default class CompositeCookieQueryStrategy implements CookieQueryStrategy
|
|
|
18
33
|
}
|
|
19
34
|
|
|
20
35
|
async queryCookies(name: string, domain: string): Promise<ExportedCookie[]> {
|
|
21
|
-
|
|
22
|
-
|
|
36
|
+
// domain = domain.match(/(\w+.+\w+)/gi)?.pop() ?? domain;
|
|
37
|
+
const key = `${name}:${domain}`;
|
|
38
|
+
const cached = cache.get(key);
|
|
39
|
+
if (cached) {
|
|
40
|
+
return cached;
|
|
41
|
+
}
|
|
42
|
+
if (parsedArgs.verbose) {
|
|
43
|
+
console.log("Querying cookies:", name, domain);
|
|
44
|
+
}
|
|
45
|
+
const results: ExportedCookie[][] = await Promise.all(
|
|
46
|
+
this.#strategies.map(async (strategy: CookieQueryStrategy) => {
|
|
23
47
|
// @ts-ignore
|
|
24
|
-
|
|
25
|
-
|
|
48
|
+
return strategy
|
|
49
|
+
.queryCookies(name, domain)
|
|
50
|
+
.then((cookies: ExportedCookie[]) => {
|
|
51
|
+
return cookies.map((cookie: ExportedCookie) => {
|
|
52
|
+
return merge(cookie, {
|
|
53
|
+
meta: {
|
|
54
|
+
browser: strategy.browserName,
|
|
55
|
+
},
|
|
56
|
+
});
|
|
57
|
+
});
|
|
58
|
+
})
|
|
59
|
+
.catch((e) => {
|
|
60
|
+
console.log(
|
|
61
|
+
red(`Error querying ${strategy.browserName} cookies`),
|
|
62
|
+
e
|
|
63
|
+
);
|
|
64
|
+
return [];
|
|
65
|
+
});
|
|
26
66
|
})
|
|
27
67
|
);
|
|
28
|
-
|
|
68
|
+
const flat: ExportedCookie[] = results.flat();
|
|
69
|
+
cache.set(`${name}:${domain}`, flat);
|
|
70
|
+
return flat;
|
|
29
71
|
}
|
|
30
72
|
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import
|
|
1
|
+
import ExportedCookie from "../ExportedCookie";
|
|
2
2
|
|
|
3
3
|
export default interface CookieQueryStrategy {
|
|
4
|
-
|
|
4
|
+
browserName: string;
|
|
5
|
+
queryCookies(name: string, domain: string): Promise<ExportedCookie[]>;
|
|
5
6
|
}
|