@mherod/get-cookie 2.0.0-rc.3 → 2.0.0-rc.30
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/.idea/runConfigurations/build.xml +12 -0
- package/.parcelrc +12 -0
- package/.prettierignore +5 -0
- package/.prettierrc +12 -0
- package/.terserrc +26 -0
- package/README.md +2 -2
- package/dist/cli.js +2 -0
- package/dist/index.js +2 -687
- package/dist/index.js.map +1 -0
- package/dist/module.js +1323 -0
- package/dist/module.js.map +1 -0
- package/dist/prompt.2b8c61c0.js +40 -0
- package/dist/prompt.536a2c51.js +40 -0
- package/dist/prompt.fb2c7dad.js.map +1 -0
- package/dist/types.d.ts +25 -0
- package/dist/types.d.ts.map +1 -0
- package/jest.config.ts +14 -0
- package/package-lock.json +2688 -6684
- package/package.json +42 -35
- package/src/CookieRow.ts +1 -0
- package/src/CookieSpec.ts +3 -1
- package/src/CookieStore.ts +27 -0
- package/src/ExportedCookie.ts +13 -0
- package/src/FetchResponse.ts +1 -2
- package/src/FileCookieStore.ts +175 -0
- package/src/StringToRegex.ts +16 -0
- package/src/argv.ts +29 -0
- package/src/browsers/ChromeApplicationSupport.ts +10 -0
- package/src/browsers/ChromeCookieQueryStrategy.ts +71 -131
- package/src/browsers/CompositeCookieQueryStrategy.ts +35 -11
- package/src/browsers/CookieQueryStrategy.ts +2 -0
- package/src/browsers/CookieStoreQueryStrategy.ts +99 -0
- package/src/browsers/DoSqliteQueryWithTransform.ts +85 -0
- package/src/browsers/FirefoxCookieQueryStrategy.ts +12 -7
- package/src/browsers/SafariCookieQueryStrategy.ts +3 -0
- package/src/browsers/decrypt.ts +118 -0
- package/src/browsers/getChromePassword.ts +9 -0
- package/src/cli.ts +52 -36
- package/src/comboQueryCookieSpec.ts +24 -0
- package/src/cookieSpecsFromUrl.ts +26 -0
- package/src/execSimple.ts +13 -0
- package/src/fetchWithCookies.ts +105 -38
- package/src/findAllFiles.ts +26 -54
- package/src/getChromeCookie.ts +19 -0
- package/src/getCookie.ts +20 -0
- package/src/getFirefoxCookie.ts +19 -0
- package/src/getGroupedRenderedCookies.ts +11 -24
- package/src/getMergedRenderedCookies.ts +12 -0
- package/src/global.ts +1 -1
- package/src/index.ts +14 -58
- package/src/isValidJwt.ts +4 -4
- package/src/listChromeProfiles.ts +45 -0
- package/src/logger.ts +3 -0
- package/src/queryCookies.ts +20 -11
- package/src/resultsRendered.ts +6 -3
- package/src/util/flatMapAsync.test.ts +55 -0
- package/src/util/flatMapAsync.ts +37 -0
- package/tsconfig.json +12 -16
- package/.github/dependabot.yml +0 -6
- package/.prettierrc.json +0 -1
- package/src/IsExportedCookie.ts +0 -9
- package/src/MemoryCookieStore.ts +0 -5
- package/src/browsers/MemoryCookieJarQueryStrategy.ts +0 -53
- package/src/doSqliteQuery1.ts +0 -51
- package/src/utils.ts +0 -50
|
@@ -1,18 +1,24 @@
|
|
|
1
1
|
import CookieQueryStrategy from "./CookieQueryStrategy";
|
|
2
|
-
import {
|
|
3
|
-
import { env, HOME } from "../global";
|
|
2
|
+
import { env } from "../global";
|
|
4
3
|
import { existsSync } from "fs";
|
|
5
4
|
import { findAllFiles } from "../findAllFiles";
|
|
6
|
-
import
|
|
7
|
-
import * as path from "path";
|
|
8
|
-
import { doSqliteQuery1 } from "../doSqliteQuery1";
|
|
5
|
+
import { join } from "path";
|
|
9
6
|
import { merge } from "lodash";
|
|
10
7
|
import { isCookieRow } from "../IsCookieRow";
|
|
11
|
-
import { isExportedCookie } from "../
|
|
8
|
+
import { isExportedCookie } from "../ExportedCookie";
|
|
12
9
|
import CookieRow from "../CookieRow";
|
|
13
10
|
import ExportedCookie from "../ExportedCookie";
|
|
11
|
+
import { stringToRegex } from "../StringToRegex";
|
|
12
|
+
import { parsedArgs } from "../argv";
|
|
13
|
+
import consola from "consola";
|
|
14
|
+
import { getChromePassword } from "./getChromePassword";
|
|
15
|
+
import { chromeApplicationSupport } from "./ChromeApplicationSupport";
|
|
16
|
+
import { decrypt } from "./decrypt";
|
|
17
|
+
import { doSqliteQueryWithTransform } from "./DoSqliteQueryWithTransform";
|
|
14
18
|
|
|
15
19
|
export default class ChromeCookieQueryStrategy implements CookieQueryStrategy {
|
|
20
|
+
browserName = "Chrome";
|
|
21
|
+
|
|
16
22
|
async queryCookies(name: string, domain: string): Promise<ExportedCookie[]> {
|
|
17
23
|
if (process.platform !== "darwin") {
|
|
18
24
|
throw new Error("This only works on macOS");
|
|
@@ -40,7 +46,7 @@ async function getPromise1(
|
|
|
40
46
|
file: file,
|
|
41
47
|
});
|
|
42
48
|
} catch (e) {
|
|
43
|
-
if (
|
|
49
|
+
if (parsedArgs.verbose) {
|
|
44
50
|
console.log("Error getting encrypted cookie", e);
|
|
45
51
|
}
|
|
46
52
|
return [];
|
|
@@ -50,16 +56,16 @@ async function getPromise1(
|
|
|
50
56
|
async function getPromise(name: string, domain: string): Promise<CookieRow[]> {
|
|
51
57
|
try {
|
|
52
58
|
const files: string[] = await findAllFiles({
|
|
53
|
-
path:
|
|
59
|
+
path: chromeApplicationSupport,
|
|
54
60
|
name: "Cookies",
|
|
55
61
|
});
|
|
56
62
|
const promises: Promise<CookieRow[]>[] = files.map((file) =>
|
|
57
63
|
getPromise1(name, domain, file)
|
|
58
64
|
);
|
|
59
|
-
const results1:
|
|
65
|
+
const results1: CookieRow[][] = await Promise.all(promises);
|
|
60
66
|
return results1.flat().filter(isCookieRow);
|
|
61
67
|
} catch (error) {
|
|
62
|
-
if (
|
|
68
|
+
if (parsedArgs.verbose) {
|
|
63
69
|
console.log("error", error);
|
|
64
70
|
}
|
|
65
71
|
return [];
|
|
@@ -71,7 +77,7 @@ async function decryptValue(password: string, encryptedValue: Buffer) {
|
|
|
71
77
|
try {
|
|
72
78
|
d = await decrypt(password, encryptedValue);
|
|
73
79
|
} catch (e) {
|
|
74
|
-
if (
|
|
80
|
+
if (parsedArgs.verbose) {
|
|
75
81
|
console.log("Error decrypting cookie", e);
|
|
76
82
|
}
|
|
77
83
|
d = null;
|
|
@@ -99,34 +105,37 @@ Promise<ExportedCookie[]> {
|
|
|
99
105
|
const decryptedValue = await decryptValue(password, encryptedValue);
|
|
100
106
|
const meta = {};
|
|
101
107
|
merge(meta, cookieRow.meta ?? {});
|
|
102
|
-
|
|
108
|
+
const exportedCookie: ExportedCookie = {
|
|
103
109
|
domain: cookieRow.domain,
|
|
104
110
|
name: cookieRow.name,
|
|
105
111
|
value: decryptedValue,
|
|
106
112
|
meta: meta,
|
|
107
113
|
};
|
|
114
|
+
const expiry = cookieRow.expiry;
|
|
115
|
+
const mergeExpiry =
|
|
116
|
+
expiry != null && expiry > 0
|
|
117
|
+
? {
|
|
118
|
+
expiry: new Date(expiry),
|
|
119
|
+
}
|
|
120
|
+
: {
|
|
121
|
+
expiry: "Infinity",
|
|
122
|
+
};
|
|
123
|
+
merge(exportedCookie, mergeExpiry);
|
|
124
|
+
return exportedCookie;
|
|
108
125
|
});
|
|
109
126
|
const results: ExportedCookie[] = (await Promise.all(decrypted)).filter(
|
|
110
127
|
isExportedCookie
|
|
111
128
|
);
|
|
112
|
-
if (
|
|
129
|
+
if (parsedArgs.verbose) {
|
|
113
130
|
console.log("results", results);
|
|
114
131
|
}
|
|
115
132
|
return results;
|
|
116
133
|
}
|
|
117
134
|
|
|
118
|
-
const chromeLocal = path.join(
|
|
119
|
-
HOME,
|
|
120
|
-
"Library",
|
|
121
|
-
"Application Support",
|
|
122
|
-
"Google",
|
|
123
|
-
"Chrome"
|
|
124
|
-
);
|
|
125
|
-
|
|
126
135
|
async function getEncryptedChromeCookie({
|
|
127
136
|
name,
|
|
128
137
|
domain,
|
|
129
|
-
file =
|
|
138
|
+
file = join(chromeApplicationSupport, "Default", "Cookies"),
|
|
130
139
|
}: //
|
|
131
140
|
{
|
|
132
141
|
name: string;
|
|
@@ -136,138 +145,69 @@ async function getEncryptedChromeCookie({
|
|
|
136
145
|
if (!existsSync(file)) {
|
|
137
146
|
throw new Error(`File ${file} does not exist`);
|
|
138
147
|
}
|
|
139
|
-
if (
|
|
148
|
+
if (parsedArgs.verbose) {
|
|
140
149
|
const s = file.split("/").slice(-3).join("/");
|
|
141
|
-
|
|
150
|
+
consola.start(
|
|
151
|
+
`Trying Chrome (at ${s}) cookie ${name} for domain ${domain}`
|
|
152
|
+
);
|
|
142
153
|
}
|
|
143
154
|
let sql;
|
|
144
155
|
//language=SQL
|
|
145
|
-
sql = "SELECT encrypted_value, name, host_key FROM cookies";
|
|
156
|
+
sql = "SELECT encrypted_value, name, host_key, expires_utc FROM cookies";
|
|
157
|
+
// Define a regular expression to match wildcard characters
|
|
146
158
|
const wildcardRegexp = /^([*%])$/i;
|
|
159
|
+
// Check if the name does not contain wildcard characters
|
|
147
160
|
const specifiedName = name.match(wildcardRegexp) == null;
|
|
161
|
+
// Check if the domain does not contain wildcard characters
|
|
148
162
|
const specifiedDomain = domain.match(wildcardRegexp) == null;
|
|
149
|
-
if
|
|
163
|
+
// Check if the domain contains wildcard characters
|
|
164
|
+
const wildcardDomain = domain.match(/[%*]/) != null;
|
|
165
|
+
// Determine if we should query the domain based on the previous checks
|
|
166
|
+
const queryDomain = specifiedDomain && !wildcardDomain;
|
|
167
|
+
// if we have a wildcard domain, we need to use a regexp
|
|
168
|
+
// If the name is specified or we need to query the domain, we add a WHERE clause to the SQL query
|
|
169
|
+
if (specifiedName || queryDomain) {
|
|
150
170
|
sql += ` WHERE `;
|
|
171
|
+
// If the name is specified, we add a condition to the SQL query to match the name
|
|
151
172
|
if (specifiedName) {
|
|
152
173
|
sql += `name = '${name}'`;
|
|
153
|
-
|
|
174
|
+
// If we also need to query the domain, we add an AND operator to the SQL query
|
|
175
|
+
if (queryDomain) {
|
|
154
176
|
sql += ` AND `;
|
|
155
177
|
}
|
|
156
178
|
}
|
|
157
|
-
|
|
158
|
-
|
|
179
|
+
// If we need to query the domain, we add a condition to the SQL query to match the domain
|
|
180
|
+
if (queryDomain) {
|
|
181
|
+
// The leading dot is replaced with % to match subdomains
|
|
182
|
+
const sqlEmbedDomain = domain.replace(/^[.%]?/, "%");
|
|
183
|
+
sql += `host_key LIKE '${sqlEmbedDomain}';`;
|
|
159
184
|
}
|
|
160
185
|
}
|
|
161
|
-
|
|
186
|
+
if (parsedArgs.verbose) {
|
|
187
|
+
consola.info("Querying:", sql);
|
|
188
|
+
}
|
|
189
|
+
const domainRegexp: RegExp = stringToRegex(domain);
|
|
190
|
+
const sqliteQuery1: CookieRow[] = await doSqliteQueryWithTransform({
|
|
162
191
|
file: file,
|
|
163
192
|
sql: sql,
|
|
193
|
+
rowFilter: (row) => {
|
|
194
|
+
return row["host_key"].match(domainRegexp) != null;
|
|
195
|
+
},
|
|
164
196
|
rowTransform: (row) => {
|
|
165
|
-
|
|
197
|
+
const cookieRow = {
|
|
198
|
+
expiry: (row["expires_utc"] / 1000000 - 11644473600) * 1000,
|
|
166
199
|
domain: row["host_key"],
|
|
167
200
|
name: row["name"],
|
|
168
201
|
value: row["encrypted_value"],
|
|
169
202
|
};
|
|
203
|
+
if (parsedArgs.verbose) {
|
|
204
|
+
consola.info("Found", cookieRow);
|
|
205
|
+
}
|
|
206
|
+
return cookieRow;
|
|
170
207
|
},
|
|
171
208
|
});
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
return execSimple(
|
|
176
|
-
'security find-generic-password -w -s "Chrome Safe Storage"'
|
|
177
|
-
);
|
|
178
|
-
}
|
|
179
|
-
|
|
180
|
-
async function decrypt(
|
|
181
|
-
password: crypto.BinaryLike,
|
|
182
|
-
encryptedData: Buffer
|
|
183
|
-
): Promise<string> {
|
|
184
|
-
if (typeof password !== "string") {
|
|
185
|
-
throw new Error("password must be a string: " + password);
|
|
186
|
-
}
|
|
187
|
-
let encryptedData1: any;
|
|
188
|
-
encryptedData1 = encryptedData;
|
|
189
|
-
if (encryptedData1 == null || typeof encryptedData1 !== "object") {
|
|
190
|
-
throw new Error("encryptedData must be a object: " + encryptedData1);
|
|
191
|
-
}
|
|
192
|
-
if (!(encryptedData1 instanceof Buffer)) {
|
|
193
|
-
if (Array.isArray(encryptedData1) && encryptedData1[0] instanceof Buffer) {
|
|
194
|
-
[encryptedData1] = encryptedData1;
|
|
195
|
-
if (env.VERBOSE) {
|
|
196
|
-
console.log(
|
|
197
|
-
`encryptedData is an array of buffers, selected first: ${encryptedData1}`
|
|
198
|
-
);
|
|
199
|
-
}
|
|
200
|
-
} else {
|
|
201
|
-
throw new Error("encryptedData must be a Buffer: " + encryptedData1);
|
|
202
|
-
}
|
|
203
|
-
encryptedData1 = Buffer.from(encryptedData1);
|
|
204
|
-
}
|
|
205
|
-
if (env.VERBOSE) {
|
|
206
|
-
console.log(`Trying to decrypt with password ${password}`);
|
|
207
|
-
}
|
|
208
|
-
return new Promise((resolve, reject) => {
|
|
209
|
-
crypto.pbkdf2(password, "saltysalt", 1003, 16, "sha1", (error, buffer) => {
|
|
210
|
-
try {
|
|
211
|
-
if (error) {
|
|
212
|
-
if (env.VERBOSE) {
|
|
213
|
-
console.log("Error doing pbkdf2", error);
|
|
214
|
-
}
|
|
215
|
-
reject(error);
|
|
216
|
-
return;
|
|
217
|
-
}
|
|
218
|
-
|
|
219
|
-
if (buffer.length !== 16) {
|
|
220
|
-
if (env.VERBOSE) {
|
|
221
|
-
console.log(
|
|
222
|
-
"Error doing pbkdf2, buffer length is not 16",
|
|
223
|
-
buffer.length
|
|
224
|
-
);
|
|
225
|
-
}
|
|
226
|
-
reject(new Error("Buffer length is not 16"));
|
|
227
|
-
return;
|
|
228
|
-
}
|
|
229
|
-
|
|
230
|
-
const str = new Array(17).join(" ");
|
|
231
|
-
const iv = Buffer.from(str, "binary");
|
|
232
|
-
const decipher = crypto.createDecipheriv("aes-128-cbc", buffer, iv);
|
|
233
|
-
decipher.setAutoPadding(false);
|
|
234
|
-
|
|
235
|
-
if (encryptedData1 && encryptedData1.slice) {
|
|
236
|
-
encryptedData1 = encryptedData1.slice(3);
|
|
237
|
-
}
|
|
238
|
-
|
|
239
|
-
if (encryptedData1.length % 16 !== 0) {
|
|
240
|
-
if (env.VERBOSE) {
|
|
241
|
-
console.log(
|
|
242
|
-
"Error doing pbkdf2, encryptedData length is not a multiple of 16",
|
|
243
|
-
encryptedData1.length
|
|
244
|
-
);
|
|
245
|
-
}
|
|
246
|
-
reject(new Error("encryptedData length is not a multiple of 16"));
|
|
247
|
-
return;
|
|
248
|
-
}
|
|
249
|
-
|
|
250
|
-
let decoded = decipher.update(encryptedData1);
|
|
251
|
-
try {
|
|
252
|
-
decipher.final("utf-8");
|
|
253
|
-
} catch (e) {
|
|
254
|
-
if (env.VERBOSE) {
|
|
255
|
-
console.log("Error doing decipher.final()", e);
|
|
256
|
-
}
|
|
257
|
-
reject(e);
|
|
258
|
-
return;
|
|
259
|
-
}
|
|
260
|
-
|
|
261
|
-
const padding = decoded[decoded.length - 1];
|
|
262
|
-
if (padding) {
|
|
263
|
-
decoded = decoded.slice(0, 0 - padding);
|
|
264
|
-
}
|
|
265
|
-
// noinspection JSCheckFunctionSignatures
|
|
266
|
-
const decodedString = decoded.toString("utf8");
|
|
267
|
-
resolve(decodedString);
|
|
268
|
-
} catch (e) {
|
|
269
|
-
reject(e);
|
|
270
|
-
}
|
|
271
|
-
});
|
|
209
|
+
return sqliteQuery1.filter((row) => {
|
|
210
|
+
// TODO: is this needed?
|
|
211
|
+
return row.domain.match(domainRegexp) != null;
|
|
272
212
|
});
|
|
273
213
|
}
|
|
@@ -4,21 +4,28 @@ import SafariCookieQueryStrategy from "./SafariCookieQueryStrategy";
|
|
|
4
4
|
import CookieQueryStrategy from "./CookieQueryStrategy";
|
|
5
5
|
import ExportedCookie from "../ExportedCookie";
|
|
6
6
|
import LRUCache from "lru-cache";
|
|
7
|
-
import
|
|
7
|
+
import { red } from "colorette";
|
|
8
|
+
import { merge } from "lodash";
|
|
9
|
+
import { parsedArgs } from "../argv";
|
|
8
10
|
|
|
9
|
-
const cache
|
|
10
|
-
|
|
11
|
+
const cache: LRUCache<string, ExportedCookie[]> = new LRUCache<
|
|
12
|
+
string,
|
|
13
|
+
ExportedCookie[]
|
|
14
|
+
>({
|
|
15
|
+
ttl: 1000 * 10,
|
|
11
16
|
max: 10,
|
|
12
17
|
});
|
|
13
18
|
|
|
14
19
|
export default class CompositeCookieQueryStrategy
|
|
15
20
|
implements CookieQueryStrategy
|
|
16
21
|
{
|
|
22
|
+
browserName = "all";
|
|
23
|
+
|
|
17
24
|
#strategies;
|
|
18
25
|
|
|
19
26
|
constructor() {
|
|
20
27
|
this.#strategies = [
|
|
21
|
-
|
|
28
|
+
// CookieStoreQueryStrategy,
|
|
22
29
|
ChromeCookieQueryStrategy,
|
|
23
30
|
FirefoxCookieQueryStrategy,
|
|
24
31
|
SafariCookieQueryStrategy,
|
|
@@ -28,19 +35,36 @@ export default class CompositeCookieQueryStrategy
|
|
|
28
35
|
}
|
|
29
36
|
|
|
30
37
|
async queryCookies(name: string, domain: string): Promise<ExportedCookie[]> {
|
|
38
|
+
// domain = domain.match(/(\w+.+\w+)/gi)?.pop() ?? domain;
|
|
31
39
|
const key = `${name}:${domain}`;
|
|
32
40
|
const cached = cache.get(key);
|
|
33
41
|
if (cached) {
|
|
34
42
|
return cached;
|
|
35
43
|
}
|
|
36
|
-
|
|
37
|
-
|
|
44
|
+
if (parsedArgs.verbose) {
|
|
45
|
+
console.log("Querying cookies:", name, domain);
|
|
46
|
+
}
|
|
47
|
+
const results: ExportedCookie[][] = await Promise.all(
|
|
48
|
+
this.#strategies.map(async (strategy: CookieQueryStrategy) => {
|
|
38
49
|
// @ts-ignore
|
|
39
|
-
|
|
40
|
-
name,
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
50
|
+
return strategy
|
|
51
|
+
.queryCookies(name, domain)
|
|
52
|
+
.then((cookies: ExportedCookie[]) => {
|
|
53
|
+
return cookies.map((cookie: ExportedCookie) => {
|
|
54
|
+
return merge(cookie, {
|
|
55
|
+
meta: {
|
|
56
|
+
browser: strategy.browserName,
|
|
57
|
+
},
|
|
58
|
+
});
|
|
59
|
+
});
|
|
60
|
+
})
|
|
61
|
+
.catch((e) => {
|
|
62
|
+
console.log(
|
|
63
|
+
red(`Error querying ${strategy.browserName} cookies`),
|
|
64
|
+
e
|
|
65
|
+
);
|
|
66
|
+
return [];
|
|
67
|
+
});
|
|
44
68
|
})
|
|
45
69
|
);
|
|
46
70
|
const flat: ExportedCookie[] = results.flat();
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import CookieQueryStrategy from "./CookieQueryStrategy";
|
|
2
|
+
import CookieSpec from "../CookieSpec";
|
|
3
|
+
import ExportedCookie from "../ExportedCookie";
|
|
4
|
+
import { Cookie, Store } from "tough-cookie";
|
|
5
|
+
import { cookieJarPromise, cookieStorePromise } from "../CookieStore";
|
|
6
|
+
import { stringToRegex } from "../StringToRegex";
|
|
7
|
+
|
|
8
|
+
export default class CookieStoreQueryStrategy implements CookieQueryStrategy {
|
|
9
|
+
browserName = "internal";
|
|
10
|
+
|
|
11
|
+
async queryCookies(name: string, domain: string): Promise<ExportedCookie[]> {
|
|
12
|
+
const exportedCookies: ExportedCookie[] = [];
|
|
13
|
+
|
|
14
|
+
// if (name.match(/[%*]/) || domain.match(/[%*]/)) {
|
|
15
|
+
const cookies: Cookie[] = await this.#getAllCookies();
|
|
16
|
+
const allExportedCookies = cookies.map((cookie: Cookie) => {
|
|
17
|
+
return this.#extracted(cookie, { name, domain });
|
|
18
|
+
});
|
|
19
|
+
exportedCookies.push(...allExportedCookies);
|
|
20
|
+
// }
|
|
21
|
+
|
|
22
|
+
const wildcardRegexp = /^([*%])$/i;
|
|
23
|
+
if (name.match(wildcardRegexp) && domain.match(wildcardRegexp)) {
|
|
24
|
+
return exportedCookies;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
const path = "/";
|
|
28
|
+
|
|
29
|
+
if (domain != "%") {
|
|
30
|
+
const domain1 = domain.match(/(\w+.+\w+)/gi)?.pop() ?? domain;
|
|
31
|
+
const url = new URL("https://" + domain1);
|
|
32
|
+
url.pathname = path;
|
|
33
|
+
const cookies: Cookie[] = await this.#getCookies(url.href);
|
|
34
|
+
const domainCookies = cookies.map((cookie: Cookie) => {
|
|
35
|
+
return this.#extracted(cookie, {
|
|
36
|
+
domain,
|
|
37
|
+
name,
|
|
38
|
+
});
|
|
39
|
+
});
|
|
40
|
+
exportedCookies.push(...domainCookies);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
if (name == "%") {
|
|
44
|
+
return exportedCookies.filter((cookie: ExportedCookie) => {
|
|
45
|
+
return cookie.domain.match(stringToRegex(domain));
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
return exportedCookies.filter((cookie: ExportedCookie) => {
|
|
50
|
+
return (
|
|
51
|
+
cookie.name.match(stringToRegex(name)) &&
|
|
52
|
+
cookie.domain.match(stringToRegex(domain))
|
|
53
|
+
);
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
#extracted(cookie: Cookie, cookieSpec: CookieSpec): ExportedCookie {
|
|
58
|
+
return {
|
|
59
|
+
domain: cookie.domain ?? cookieSpec.domain,
|
|
60
|
+
name: cookie.key ?? cookieSpec.name,
|
|
61
|
+
value: cookie.value,
|
|
62
|
+
expiry: cookie.expires ?? "Infinity",
|
|
63
|
+
meta: {
|
|
64
|
+
file: "tough-cookie",
|
|
65
|
+
},
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
async #getCookies(url: string): Promise<Cookie[]> {
|
|
70
|
+
const cookieJar = await cookieJarPromise;
|
|
71
|
+
return new Promise((resolve, reject) => {
|
|
72
|
+
return cookieJar.getCookies(
|
|
73
|
+
url,
|
|
74
|
+
(err: Error | null, cookies: Cookie[]) => {
|
|
75
|
+
if (err) {
|
|
76
|
+
reject(err);
|
|
77
|
+
} else {
|
|
78
|
+
resolve(cookies ?? []);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
);
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
async #getAllCookies(): Promise<Cookie[]> {
|
|
86
|
+
const cookieStore: Store = await cookieStorePromise;
|
|
87
|
+
return new Promise((resolve, reject) => {
|
|
88
|
+
return cookieStore.getAllCookies(
|
|
89
|
+
(err: Error | null, cookies: Cookie[]) => {
|
|
90
|
+
if (err) {
|
|
91
|
+
reject(err);
|
|
92
|
+
} else {
|
|
93
|
+
resolve(cookies ?? []);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
);
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import CookieRow from "../CookieRow";
|
|
2
|
+
import fs from "fs";
|
|
3
|
+
import { Database } from "sqlite3";
|
|
4
|
+
import { merge } from "lodash";
|
|
5
|
+
import { parsedArgs } from "../argv";
|
|
6
|
+
import consola from "consola";
|
|
7
|
+
|
|
8
|
+
export interface DoSqliteQueryWithTransformOptions {
|
|
9
|
+
file: string;
|
|
10
|
+
sql: string;
|
|
11
|
+
rowFilter?: (row: any) => boolean;
|
|
12
|
+
rowTransform: (row: any) => CookieRow;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
function checkFileExistence(file: string) {
|
|
16
|
+
if (!file || !fs.existsSync(file)) {
|
|
17
|
+
throw new Error(`File ${file} does not exist`);
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
function createDatabase(file: string) {
|
|
22
|
+
return new Database(file);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
function transformRows(
|
|
26
|
+
//
|
|
27
|
+
rows: any[],
|
|
28
|
+
rowFilter: (row: any) => boolean,
|
|
29
|
+
rowTransform: (row: any) => CookieRow,
|
|
30
|
+
file: string
|
|
31
|
+
//
|
|
32
|
+
): CookieRow[] {
|
|
33
|
+
return rows.filter(rowFilter).map((row: any) => {
|
|
34
|
+
const metaData = {
|
|
35
|
+
meta: {
|
|
36
|
+
file: file,
|
|
37
|
+
},
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
const cookieRow: CookieRow = rowTransform(row);
|
|
41
|
+
|
|
42
|
+
return merge(metaData, cookieRow);
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export async function doSqliteQueryWithTransform(
|
|
47
|
+
//
|
|
48
|
+
{
|
|
49
|
+
//
|
|
50
|
+
file,
|
|
51
|
+
sql,
|
|
52
|
+
rowFilter = () => true,
|
|
53
|
+
rowTransform,
|
|
54
|
+
}: DoSqliteQueryWithTransformOptions
|
|
55
|
+
): //
|
|
56
|
+
Promise<CookieRow[]> {
|
|
57
|
+
checkFileExistence(file);
|
|
58
|
+
|
|
59
|
+
const db: Database = createDatabase(file);
|
|
60
|
+
|
|
61
|
+
return new Promise((resolve, reject) => {
|
|
62
|
+
db.all(sql, (err: Error, rows: any[]) => {
|
|
63
|
+
if (err) {
|
|
64
|
+
return reject(err);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
if (!rows || rows.length === 0) {
|
|
68
|
+
return resolve([]);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
const cookieRows: CookieRow[] = transformRows(
|
|
72
|
+
rows,
|
|
73
|
+
rowFilter,
|
|
74
|
+
rowTransform,
|
|
75
|
+
file
|
|
76
|
+
);
|
|
77
|
+
|
|
78
|
+
if (parsedArgs.verbose) {
|
|
79
|
+
consola.log(`Rows: ${JSON.stringify(rows)}`);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
return resolve(cookieRows);
|
|
83
|
+
});
|
|
84
|
+
});
|
|
85
|
+
}
|
|
@@ -1,20 +1,24 @@
|
|
|
1
1
|
import * as path from "path";
|
|
2
2
|
import CookieQueryStrategy from "./CookieQueryStrategy";
|
|
3
|
-
import {
|
|
3
|
+
import { HOME } from "../global";
|
|
4
4
|
import { existsSync } from "fs";
|
|
5
5
|
import { findAllFiles } from "../findAllFiles";
|
|
6
|
-
import { doSqliteQuery1 } from "../doSqliteQuery1";
|
|
7
6
|
import ExportedCookie from "../ExportedCookie";
|
|
8
7
|
import CookieRow from "../CookieRow";
|
|
9
8
|
import CookieSpec from "../CookieSpec";
|
|
10
9
|
import { specialCases } from "../SpecialCases";
|
|
10
|
+
import { parsedArgs } from "../argv";
|
|
11
|
+
import { doSqliteQueryWithTransform } from "./DoSqliteQueryWithTransform";
|
|
11
12
|
|
|
12
13
|
export default class FirefoxCookieQueryStrategy implements CookieQueryStrategy {
|
|
14
|
+
browserName = "Firefox";
|
|
15
|
+
|
|
13
16
|
async queryCookies(name: string, domain: string): Promise<ExportedCookie[]> {
|
|
14
17
|
if (process.platform !== "darwin") {
|
|
15
|
-
|
|
18
|
+
// TODO: implement
|
|
19
|
+
return [];
|
|
16
20
|
}
|
|
17
|
-
if (
|
|
21
|
+
if (parsedArgs.browser !== "firefox") {
|
|
18
22
|
return [];
|
|
19
23
|
}
|
|
20
24
|
const cookies = await this.#getFirefoxCookie({ name, domain });
|
|
@@ -34,7 +38,7 @@ export default class FirefoxCookieQueryStrategy implements CookieQueryStrategy {
|
|
|
34
38
|
async #getFirefoxCookie(
|
|
35
39
|
{ name, domain }: CookieSpec //
|
|
36
40
|
) {
|
|
37
|
-
const files: string[] =
|
|
41
|
+
const files: string[] = findAllFiles({
|
|
38
42
|
path: path.join(
|
|
39
43
|
HOME,
|
|
40
44
|
"Library",
|
|
@@ -47,7 +51,8 @@ export default class FirefoxCookieQueryStrategy implements CookieQueryStrategy {
|
|
|
47
51
|
const fn: (file: string) => Promise<CookieRow[]> = async (file: string) => {
|
|
48
52
|
return await this.#queryCookiesDb(file, name, domain);
|
|
49
53
|
};
|
|
50
|
-
const all:
|
|
54
|
+
const all: CookieRow[][] = await Promise.all(files.map(fn));
|
|
55
|
+
// flatten
|
|
51
56
|
return all.flat();
|
|
52
57
|
}
|
|
53
58
|
|
|
@@ -85,7 +90,7 @@ export default class FirefoxCookieQueryStrategy implements CookieQueryStrategy {
|
|
|
85
90
|
};
|
|
86
91
|
};
|
|
87
92
|
try {
|
|
88
|
-
return await
|
|
93
|
+
return await doSqliteQueryWithTransform({
|
|
89
94
|
file,
|
|
90
95
|
sql,
|
|
91
96
|
rowTransform,
|
|
@@ -2,7 +2,10 @@ import CookieQueryStrategy from "./CookieQueryStrategy";
|
|
|
2
2
|
import ExportedCookie from "../ExportedCookie";
|
|
3
3
|
|
|
4
4
|
export default class SafariCookieQueryStrategy implements CookieQueryStrategy {
|
|
5
|
+
browserName = "Safari";
|
|
6
|
+
|
|
5
7
|
async queryCookies(name: string, domain: string): Promise<ExportedCookie[]> {
|
|
8
|
+
// TODO: implement
|
|
6
9
|
return [];
|
|
7
10
|
}
|
|
8
11
|
}
|