@mherod/get-cookie 1.1.5 → 1.2.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 +2 -0
- package/cli.js +48 -0
- package/index.js +160 -225
- package/package.json +7 -3
- package/utils.js +175 -0
package/README.md
CHANGED
|
@@ -11,6 +11,8 @@ To install get-cookie, run the following command:
|
|
|
11
11
|
|
|
12
12
|
$ npm install @mherod/get-cookie --global
|
|
13
13
|
|
|
14
|
+
**Note: Currently only macOS is supported. Windows support is planned for a future release.**
|
|
15
|
+
|
|
14
16
|
## How do I use it?
|
|
15
17
|
|
|
16
18
|
To use get-cookie, run the following command:
|
package/cli.js
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
const {getCookie} = require("./index");
|
|
4
|
+
|
|
5
|
+
if (process.argv) {
|
|
6
|
+
if (process.argv.length > 2) {
|
|
7
|
+
const name = process.argv[2];
|
|
8
|
+
|
|
9
|
+
let domain;
|
|
10
|
+
if (process.argv[3] != null && process.argv[3].indexOf(".") > -1) {
|
|
11
|
+
domain = process.argv[3];
|
|
12
|
+
} else {
|
|
13
|
+
domain = '%';
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
if (process.argv.includes("--require-jwt")) {
|
|
17
|
+
process.env.REQUIRE_JWT = "true";
|
|
18
|
+
}
|
|
19
|
+
if (process.argv.includes('--verbose')) {
|
|
20
|
+
process.env.VERBOSE = "true";
|
|
21
|
+
}
|
|
22
|
+
if (process.argv.includes("--chrome-only")) {
|
|
23
|
+
process.env.CHROME_ONLY = "true";
|
|
24
|
+
}
|
|
25
|
+
if (process.argv.includes("--firefox-only")) {
|
|
26
|
+
process.env.FIREFOX_ONLY = "true";
|
|
27
|
+
}
|
|
28
|
+
if (process.argv.includes("--ignore-expired")) {
|
|
29
|
+
process.env.IGNORE_EXPIRED = "true";
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
if (process.env.VERBOSE) {
|
|
33
|
+
console.log("Verbose mode", process.argv);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
getCookie({
|
|
37
|
+
name: name,
|
|
38
|
+
domain: domain,
|
|
39
|
+
requireJwt: (process.env.REQUIRE_JWT === "true"),
|
|
40
|
+
}).then(cookie => {
|
|
41
|
+
if (typeof cookie === "string") {
|
|
42
|
+
console.log(cookie);
|
|
43
|
+
}
|
|
44
|
+
}).catch(err => {
|
|
45
|
+
console.error(err);
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
}
|
package/index.js
CHANGED
|
@@ -1,11 +1,27 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
|
+
if (process.platform !== 'darwin') {
|
|
4
|
+
throw new Error('This script only works on macOS');
|
|
5
|
+
}
|
|
6
|
+
|
|
3
7
|
const crypto = require('crypto');
|
|
4
|
-
const {exec} = require("child_process");
|
|
5
8
|
const fs = require("fs");
|
|
9
|
+
const {execSimple, toStringOrNull, doSqliteQuery1, printStringValue, toStringValue} = require("./utils");
|
|
10
|
+
const jsonwebtoken = require('jsonwebtoken');
|
|
6
11
|
|
|
7
|
-
|
|
8
|
-
|
|
12
|
+
function isValidJwt(token) {
|
|
13
|
+
if (typeof token !== 'string') {
|
|
14
|
+
return false;
|
|
15
|
+
}
|
|
16
|
+
try {
|
|
17
|
+
const result = jsonwebtoken.decode(token, {complete: true});
|
|
18
|
+
if (process.env.VERBOSE) {
|
|
19
|
+
console.log(result);
|
|
20
|
+
}
|
|
21
|
+
return true;
|
|
22
|
+
} catch (err) {
|
|
23
|
+
return false;
|
|
24
|
+
}
|
|
9
25
|
}
|
|
10
26
|
|
|
11
27
|
/**
|
|
@@ -13,24 +29,74 @@ if (process.platform !== 'darwin') {
|
|
|
13
29
|
* @returns {Promise<string>}
|
|
14
30
|
*/
|
|
15
31
|
async function getChromePassword() {
|
|
16
|
-
return await
|
|
17
|
-
exec("security find-generic-password -w -s \"Chrome Safe Storage\"", (error, stdout, stderr) => {
|
|
18
|
-
if (error) {
|
|
19
|
-
reject(error);
|
|
20
|
-
return;
|
|
21
|
-
}
|
|
22
|
-
if (stderr) {
|
|
23
|
-
reject(error);
|
|
24
|
-
return;
|
|
25
|
-
}
|
|
26
|
-
let s = stdout.toString().trim();
|
|
27
|
-
resolve(s);
|
|
28
|
-
});
|
|
29
|
-
});
|
|
32
|
+
return await execSimple("security find-generic-password -w -s \"Chrome Safe Storage\"");
|
|
30
33
|
}
|
|
31
34
|
|
|
32
|
-
|
|
33
|
-
|
|
35
|
+
/**
|
|
36
|
+
*
|
|
37
|
+
* @param params
|
|
38
|
+
* @returns {Promise<string>}
|
|
39
|
+
*/
|
|
40
|
+
async function getCookie(params) {
|
|
41
|
+
if (process.env.CHROME_ONLY) {
|
|
42
|
+
if (process.env.VERBOSE) {
|
|
43
|
+
console.log('chrome only');
|
|
44
|
+
}
|
|
45
|
+
return await getChromeCookie(params)
|
|
46
|
+
.then(cookie => {
|
|
47
|
+
if (cookie && cookie.length > 0) {
|
|
48
|
+
return toStringValue(cookie);
|
|
49
|
+
}
|
|
50
|
+
})
|
|
51
|
+
.catch(err => {
|
|
52
|
+
if (process.env.VERBOSE) {
|
|
53
|
+
console.error(err);
|
|
54
|
+
}
|
|
55
|
+
});
|
|
56
|
+
} else if (process.env.FIREFOX_ONLY) {
|
|
57
|
+
if (process.env.VERBOSE) {
|
|
58
|
+
console.log('firefox only');
|
|
59
|
+
}
|
|
60
|
+
return await getFirefoxCookie(params)
|
|
61
|
+
.then(b => b.toString('utf8'))
|
|
62
|
+
.then(cookie => {
|
|
63
|
+
if (cookie && cookie.length > 0) {
|
|
64
|
+
return toStringValue(cookie);
|
|
65
|
+
} else {
|
|
66
|
+
console.log('No cookie found');
|
|
67
|
+
}
|
|
68
|
+
})
|
|
69
|
+
.catch(err => {
|
|
70
|
+
if (process.env.VERBOSE) {
|
|
71
|
+
console.error("Error getting Firefox cookie", err);
|
|
72
|
+
}
|
|
73
|
+
});
|
|
74
|
+
} else {
|
|
75
|
+
return await getChromeCookie(params)
|
|
76
|
+
.catch(err => {
|
|
77
|
+
if (process.env.VERBOSE) {
|
|
78
|
+
console.error("Error getting Chrome cookie", err);
|
|
79
|
+
}
|
|
80
|
+
})
|
|
81
|
+
.then(r => {
|
|
82
|
+
if (typeof r === 'string' && r.trim().length > 0) {
|
|
83
|
+
return r;
|
|
84
|
+
} else {
|
|
85
|
+
return getFirefoxCookie(params)
|
|
86
|
+
.catch(err => {
|
|
87
|
+
if (process.env.VERBOSE) {
|
|
88
|
+
console.error("Error getting Firefox cookie", err);
|
|
89
|
+
}
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
})
|
|
93
|
+
.catch((e) => {
|
|
94
|
+
if (process.env.VERBOSE) {
|
|
95
|
+
console.error("Error getting Chrome or Firefox cookie", e);
|
|
96
|
+
}
|
|
97
|
+
})
|
|
98
|
+
.then(toStringValue);
|
|
99
|
+
}
|
|
34
100
|
}
|
|
35
101
|
|
|
36
102
|
/**
|
|
@@ -46,8 +112,11 @@ async function getFirefoxCookie({name, domain}) {
|
|
|
46
112
|
if (domain && typeof domain !== 'string') {
|
|
47
113
|
throw new Error('domain must be a string');
|
|
48
114
|
}
|
|
49
|
-
const file = await
|
|
50
|
-
|
|
115
|
+
const [file] = await findAllFiles({
|
|
116
|
+
path: `${process.env.HOME}/Library/Application Support/Firefox/Profiles`,
|
|
117
|
+
name: "cookies.sqlite"
|
|
118
|
+
})
|
|
119
|
+
if (file && !fs.existsSync(file)) {
|
|
51
120
|
throw new Error(`File ${file} does not exist`);
|
|
52
121
|
}
|
|
53
122
|
if (process.env.VERBOSE) {
|
|
@@ -67,7 +136,9 @@ async function getFirefoxCookie({name, domain}) {
|
|
|
67
136
|
sql += `host LIKE '${domain}';`;
|
|
68
137
|
}
|
|
69
138
|
}
|
|
70
|
-
return await doSqliteQuery1(file, sql)
|
|
139
|
+
return await doSqliteQuery1(file, sql).then(rows => {
|
|
140
|
+
return rows.map(toStringOrNull).find(v => v !== null);
|
|
141
|
+
});
|
|
71
142
|
}
|
|
72
143
|
|
|
73
144
|
const defaultChromeRoot = `${process.env.HOME}/Library/Application Support/Google/Chrome`;
|
|
@@ -87,7 +158,7 @@ async function getEncryptedChromeCookie({name, domain, file = defaultChromeCooki
|
|
|
87
158
|
throw new Error(`File ${file} does not exist`);
|
|
88
159
|
}
|
|
89
160
|
if (process.env.VERBOSE) {
|
|
90
|
-
console.log(`Trying Chrome (at ${file}) cookie ${name} for domain ${domain}`);
|
|
161
|
+
console.log(`Trying Chrome (at ${file.split('/').slice(-3).join('/')}) cookie ${name} for domain ${domain}`);
|
|
91
162
|
}
|
|
92
163
|
let sql;
|
|
93
164
|
sql = `SELECT encrypted_value FROM cookies`;
|
|
@@ -106,75 +177,32 @@ async function getEncryptedChromeCookie({name, domain, file = defaultChromeCooki
|
|
|
106
177
|
return await doSqliteQuery1(file, sql);
|
|
107
178
|
}
|
|
108
179
|
|
|
109
|
-
async function doSqliteQuery1(file, sql) {
|
|
110
|
-
const sqlite3 = require('sqlite3');
|
|
111
|
-
const db = new sqlite3.Database(file);
|
|
112
|
-
return new Promise((resolve, reject) => {
|
|
113
|
-
db.all(sql, (err, rows) => {
|
|
114
|
-
if (err) {
|
|
115
|
-
reject(err);
|
|
116
|
-
return;
|
|
117
|
-
}
|
|
118
|
-
const rows1 = rows;
|
|
119
|
-
if (rows1.length === 0) {
|
|
120
|
-
if (process.env.VERBOSE) {
|
|
121
|
-
console.log(`No rows found`);
|
|
122
|
-
}
|
|
123
|
-
resolve(null);
|
|
124
|
-
return;
|
|
125
|
-
}
|
|
126
|
-
if (Array.isArray(rows1)) {
|
|
127
|
-
// noinspection JSCheckFunctionSignatures
|
|
128
|
-
const [value] = rows1.flatMap(row => Object.values(row));
|
|
129
|
-
resolve(Buffer.from(value));
|
|
130
|
-
return;
|
|
131
|
-
}
|
|
132
|
-
resolve(rows1);
|
|
133
|
-
});
|
|
134
|
-
});
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
async function doSqliteQuery(file, sql) {
|
|
138
|
-
const command = `sqlite3 "${file}" "${sql}"`;
|
|
139
|
-
if (process.env.VERBOSE) {
|
|
140
|
-
console.log(command);
|
|
141
|
-
}
|
|
142
|
-
return await new Promise((resolve, reject) => {
|
|
143
|
-
exec(command, {encoding: 'binary', maxBuffer: 5 * 1024}, (error, stdout, stderr) => {
|
|
144
|
-
if (error) {
|
|
145
|
-
reject(error);
|
|
146
|
-
return;
|
|
147
|
-
}
|
|
148
|
-
if (stderr) {
|
|
149
|
-
reject(error);
|
|
150
|
-
return;
|
|
151
|
-
}
|
|
152
|
-
let stdoutAsBuffer = stdout;
|
|
153
|
-
if (typeof stdoutAsBuffer === 'string' && stdoutAsBuffer.length > 0) {
|
|
154
|
-
// noinspection JSCheckFunctionSignatures
|
|
155
|
-
stdoutAsBuffer = Buffer.from(stdoutAsBuffer, 'binary').slice(0, -1);
|
|
156
|
-
}
|
|
157
|
-
if (stdoutAsBuffer && stdoutAsBuffer.length > 0) {
|
|
158
|
-
resolve(stdoutAsBuffer);
|
|
159
|
-
}
|
|
160
|
-
});
|
|
161
|
-
});
|
|
162
|
-
}
|
|
163
|
-
|
|
164
180
|
/**
|
|
165
181
|
*
|
|
166
182
|
* @param {string} password
|
|
167
|
-
* @param encryptedData
|
|
183
|
+
* @param {Buffer} encryptedData
|
|
168
184
|
* @returns {Promise<string>}
|
|
169
185
|
*/
|
|
170
186
|
async function decrypt(password, encryptedData) {
|
|
171
187
|
if (typeof password !== 'string') {
|
|
172
188
|
throw new Error('password must be a string: ' + password);
|
|
173
189
|
}
|
|
174
|
-
|
|
190
|
+
let encryptedData1;
|
|
191
|
+
encryptedData1 = encryptedData;
|
|
175
192
|
if (encryptedData1 == null || typeof encryptedData1 !== 'object') {
|
|
176
193
|
throw new Error('encryptedData must be a object: ' + encryptedData1);
|
|
177
194
|
}
|
|
195
|
+
if (!(encryptedData1 instanceof Buffer)) {
|
|
196
|
+
if (Array.isArray(encryptedData1) && encryptedData1[0] instanceof Buffer) {
|
|
197
|
+
[encryptedData1] = encryptedData1;
|
|
198
|
+
if (process.env.VERBOSE) {
|
|
199
|
+
console.log(`encryptedData is an array of buffers, selected first: ${encryptedData1}`);
|
|
200
|
+
}
|
|
201
|
+
} else {
|
|
202
|
+
throw new Error('encryptedData must be a Buffer: ' + encryptedData1);
|
|
203
|
+
}
|
|
204
|
+
encryptedData1 = Buffer.from(encryptedData1);
|
|
205
|
+
}
|
|
178
206
|
if (process.env.VERBOSE) {
|
|
179
207
|
console.log(`Trying to decrypt with password ${password}`);
|
|
180
208
|
}
|
|
@@ -202,7 +230,7 @@ async function decrypt(password, encryptedData) {
|
|
|
202
230
|
decipher.setAutoPadding(false);
|
|
203
231
|
|
|
204
232
|
if (encryptedData1 && encryptedData1.slice) {
|
|
205
|
-
|
|
233
|
+
encryptedData1 = encryptedData1.slice(3);
|
|
206
234
|
}
|
|
207
235
|
|
|
208
236
|
if (encryptedData1.length % 16 !== 0) {
|
|
@@ -213,8 +241,7 @@ async function decrypt(password, encryptedData) {
|
|
|
213
241
|
return;
|
|
214
242
|
}
|
|
215
243
|
|
|
216
|
-
let decoded = decipher.update(encryptedData1
|
|
217
|
-
// let decoded = decipher.update(encryptedData);
|
|
244
|
+
let decoded = decipher.update(encryptedData1);
|
|
218
245
|
try {
|
|
219
246
|
decipher.final('utf-8');
|
|
220
247
|
} catch (e) {
|
|
@@ -242,55 +269,81 @@ async function decrypt(password, encryptedData) {
|
|
|
242
269
|
/**
|
|
243
270
|
*
|
|
244
271
|
* @param {string|undefined} name
|
|
245
|
-
* @param {string
|
|
272
|
+
* @param {string} domain
|
|
273
|
+
* @param {boolean} requireJwt
|
|
246
274
|
* @returns {Promise<string>}
|
|
247
275
|
*/
|
|
248
|
-
async function getChromeCookie({name, domain}) {
|
|
276
|
+
async function getChromeCookie({name, domain = '%', requireJwt = false}) {
|
|
249
277
|
if (name && typeof name !== 'string') {
|
|
250
278
|
throw new Error('name must be a string');
|
|
251
279
|
}
|
|
252
|
-
if (
|
|
280
|
+
if (typeof domain !== 'string') {
|
|
253
281
|
throw new Error('domain must be a string');
|
|
254
282
|
}
|
|
255
|
-
const
|
|
256
|
-
const [encryptedData] = await findAllFiles({
|
|
283
|
+
const encryptedDataItems = await findAllFiles({
|
|
257
284
|
path: defaultChromeRoot,
|
|
258
285
|
name: 'Cookies'
|
|
259
286
|
}).then(files => {
|
|
260
|
-
const
|
|
287
|
+
const promises = files.map(file => {
|
|
261
288
|
return getEncryptedChromeCookie({
|
|
262
289
|
name: name,
|
|
263
290
|
domain: domain,
|
|
264
291
|
file: file
|
|
292
|
+
}).catch(e => {
|
|
293
|
+
if (process.env.VERBOSE) {
|
|
294
|
+
console.log("Error getting encrypted cookie", e);
|
|
295
|
+
}
|
|
296
|
+
return [];
|
|
265
297
|
});
|
|
266
|
-
})
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
298
|
+
});
|
|
299
|
+
return Promise.all(promises).then(results => results.flat()).then(results => {
|
|
300
|
+
if (process.env.VERBOSE) {
|
|
301
|
+
console.log("getEncryptedChromeCookie results", results);
|
|
302
|
+
}
|
|
303
|
+
return results.filter(result => {
|
|
304
|
+
return result;
|
|
305
|
+
});
|
|
306
|
+
});
|
|
271
307
|
}).catch(error => {
|
|
272
308
|
if (process.env.VERBOSE) {
|
|
273
309
|
console.log('error', error);
|
|
274
310
|
}
|
|
275
311
|
return [];
|
|
276
312
|
});
|
|
277
|
-
const password = await
|
|
313
|
+
const password = await getChromePassword();
|
|
278
314
|
if (process.env.VERBOSE) {
|
|
279
|
-
console.log(
|
|
315
|
+
console.log('encryptedDataItems', encryptedDataItems);
|
|
280
316
|
}
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
} catch (e) {
|
|
317
|
+
const decrypted = encryptedDataItems.filter(encryptedData => {
|
|
318
|
+
return encryptedData != null && encryptedData.length > 0;
|
|
319
|
+
}).map(async encryptedData => {
|
|
285
320
|
if (process.env.VERBOSE) {
|
|
286
|
-
console.
|
|
321
|
+
console.log("Received encrypted", encryptedData);
|
|
287
322
|
}
|
|
288
|
-
|
|
289
|
-
|
|
323
|
+
let decrypted;
|
|
324
|
+
try {
|
|
325
|
+
decrypted = await decrypt(password, encryptedData);
|
|
326
|
+
} catch (e) {
|
|
327
|
+
if (process.env.VERBOSE) {
|
|
328
|
+
console.log("Error decrypting cookie", e);
|
|
329
|
+
}
|
|
330
|
+
return null;
|
|
331
|
+
}
|
|
332
|
+
if (decrypted) {
|
|
333
|
+
if (process.env.VERBOSE) {
|
|
334
|
+
console.log("Decrypted", decrypted);
|
|
335
|
+
}
|
|
336
|
+
return decrypted;
|
|
337
|
+
}
|
|
338
|
+
return null;
|
|
339
|
+
});
|
|
340
|
+
const results = await Promise.all(decrypted);
|
|
290
341
|
if (process.env.VERBOSE) {
|
|
291
|
-
console.log(
|
|
342
|
+
console.log('results', results);
|
|
292
343
|
}
|
|
293
|
-
return
|
|
344
|
+
return results.map(toStringOrNull).find(result => {
|
|
345
|
+
return typeof result === 'string' && result.length > 0 && (requireJwt === false || isValidJwt(result));
|
|
346
|
+
});
|
|
294
347
|
}
|
|
295
348
|
|
|
296
349
|
/**
|
|
@@ -361,129 +414,11 @@ async function findAllFiles({path, name, rootSegments = path.split('/').length,
|
|
|
361
414
|
return files;
|
|
362
415
|
}
|
|
363
416
|
|
|
364
|
-
/**
|
|
365
|
-
*
|
|
366
|
-
* @param path
|
|
367
|
-
* @param name
|
|
368
|
-
* @returns {Promise<string>}
|
|
369
|
-
*/
|
|
370
|
-
async function findFile(path, name) {
|
|
371
|
-
return await new Promise((resolve, reject) => {
|
|
372
|
-
for (const file of fs.readdirSync(path)) {
|
|
373
|
-
const filePath = path + '/' + file;
|
|
374
|
-
const stat = fs.statSync(filePath);
|
|
375
|
-
if (stat.isDirectory()) {
|
|
376
|
-
findFile(filePath, name).then(resolve).catch(reject);
|
|
377
|
-
} else if (file === name) {
|
|
378
|
-
resolve(filePath);
|
|
379
|
-
}
|
|
380
|
-
}
|
|
381
|
-
});
|
|
382
|
-
}
|
|
383
|
-
|
|
384
|
-
function printStringValue(r) {
|
|
385
|
-
if (process.env.VERBOSE) {
|
|
386
|
-
console.log("Printing value", r);
|
|
387
|
-
}
|
|
388
|
-
if (r) {
|
|
389
|
-
if (typeof r === 'string') {
|
|
390
|
-
console.log(r);
|
|
391
|
-
} else if (r.toString) {
|
|
392
|
-
// noinspection JSCheckFunctionSignatures
|
|
393
|
-
console.log(r.toString('utf8'));
|
|
394
|
-
}
|
|
395
|
-
}
|
|
396
|
-
}
|
|
397
|
-
|
|
398
417
|
// noinspection JSUnusedGlobalSymbols
|
|
399
418
|
module.exports = {
|
|
400
419
|
getDecryptedCookie: getChromeCookie,
|
|
401
420
|
getChromeCookie,
|
|
402
421
|
getFirefoxCookie,
|
|
403
|
-
getCookie
|
|
422
|
+
getCookie,
|
|
423
|
+
decrypt
|
|
404
424
|
};
|
|
405
|
-
|
|
406
|
-
if (process.argv) {
|
|
407
|
-
if (process.argv.length > 2) {
|
|
408
|
-
const name = process.argv[2];
|
|
409
|
-
const domain = process.argv[3] ?? '%';
|
|
410
|
-
|
|
411
|
-
if (process.argv.includes('--verbose')) {
|
|
412
|
-
process.env.VERBOSE = "true";
|
|
413
|
-
}
|
|
414
|
-
if (process.argv.includes("--chrome-only")) {
|
|
415
|
-
process.env.CHROME_ONLY = "true";
|
|
416
|
-
}
|
|
417
|
-
if (process.argv.includes("--firefox-only")) {
|
|
418
|
-
process.env.FIREFOX_ONLY = "true";
|
|
419
|
-
}
|
|
420
|
-
if (process.argv.includes("--ignore-expired")) {
|
|
421
|
-
process.env.IGNORE_EXPIRED = "true";
|
|
422
|
-
}
|
|
423
|
-
|
|
424
|
-
if (process.env.VERBOSE) {
|
|
425
|
-
console.log("Verbose mode", process.argv);
|
|
426
|
-
}
|
|
427
|
-
|
|
428
|
-
if (process.env.CHROME_ONLY) {
|
|
429
|
-
if (process.env.VERBOSE) {
|
|
430
|
-
console.log('chrome only');
|
|
431
|
-
}
|
|
432
|
-
getChromeCookie({name, domain})
|
|
433
|
-
.then(cookie => {
|
|
434
|
-
if (cookie && cookie.length > 0) {
|
|
435
|
-
printStringValue(cookie);
|
|
436
|
-
} else {
|
|
437
|
-
console.log('No cookie found');
|
|
438
|
-
}
|
|
439
|
-
})
|
|
440
|
-
.catch(err => {
|
|
441
|
-
if (process.env.VERBOSE) {
|
|
442
|
-
console.error(err);
|
|
443
|
-
}
|
|
444
|
-
});
|
|
445
|
-
} else if (process.env.FIREFOX_ONLY) {
|
|
446
|
-
if (process.env.VERBOSE) {
|
|
447
|
-
console.log('firefox only');
|
|
448
|
-
}
|
|
449
|
-
getFirefoxCookie({name, domain})
|
|
450
|
-
.then(cookie => {
|
|
451
|
-
if (cookie && cookie.length > 0) {
|
|
452
|
-
printStringValue(cookie);
|
|
453
|
-
} else {
|
|
454
|
-
console.log('No cookie found');
|
|
455
|
-
}
|
|
456
|
-
})
|
|
457
|
-
.catch(err => {
|
|
458
|
-
if (process.env.VERBOSE) {
|
|
459
|
-
console.error("Error getting Firefox cookie", err);
|
|
460
|
-
}
|
|
461
|
-
});
|
|
462
|
-
} else {
|
|
463
|
-
getChromeCookie({name, domain})
|
|
464
|
-
.catch(err => {
|
|
465
|
-
if (process.env.VERBOSE) {
|
|
466
|
-
console.error("Error getting Chrome cookie", err);
|
|
467
|
-
}
|
|
468
|
-
})
|
|
469
|
-
.then(r => {
|
|
470
|
-
if (typeof r === 'string' && r.trim().length > 0) {
|
|
471
|
-
return r;
|
|
472
|
-
} else {
|
|
473
|
-
return getFirefoxCookie({name, domain})
|
|
474
|
-
.catch(err => {
|
|
475
|
-
if (process.env.VERBOSE) {
|
|
476
|
-
console.error("Error getting Firefox cookie", err);
|
|
477
|
-
}
|
|
478
|
-
});
|
|
479
|
-
}
|
|
480
|
-
})
|
|
481
|
-
.catch((e) => {
|
|
482
|
-
if (process.env.VERBOSE) {
|
|
483
|
-
console.error("Error getting Chrome or Firefox cookie", e);
|
|
484
|
-
}
|
|
485
|
-
})
|
|
486
|
-
.then(printStringValue);
|
|
487
|
-
}
|
|
488
|
-
}
|
|
489
|
-
}
|
package/package.json
CHANGED
|
@@ -1,20 +1,24 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mherod/get-cookie",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.2.0",
|
|
4
4
|
"description": "Node.js module for querying a local user's Chrome cookie",
|
|
5
5
|
"main": "index.js",
|
|
6
|
-
"bin": "
|
|
6
|
+
"bin": "cli.js",
|
|
7
7
|
"publishConfig": {
|
|
8
8
|
"access": "public"
|
|
9
9
|
},
|
|
10
10
|
"scripts": {
|
|
11
|
-
"test": "
|
|
11
|
+
"test": "jest",
|
|
12
12
|
"installGlobal": "rm -rf /usr/local/bin/get-cookie ; npm install --force --global ."
|
|
13
13
|
},
|
|
14
14
|
"keywords": [],
|
|
15
15
|
"author": "Matthew Herod",
|
|
16
16
|
"license": "ISC",
|
|
17
17
|
"dependencies": {
|
|
18
|
+
"jsonwebtoken": "^8.5.1",
|
|
18
19
|
"sqlite3": "^5.0.8"
|
|
20
|
+
},
|
|
21
|
+
"devDependencies": {
|
|
22
|
+
"jest": "^28.1.0"
|
|
19
23
|
}
|
|
20
24
|
}
|
package/utils.js
ADDED
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
// noinspection JSUnusedGlobalSymbols
|
|
2
|
+
|
|
3
|
+
const {exec} = require('child_process');
|
|
4
|
+
const fs = require("fs");
|
|
5
|
+
|
|
6
|
+
async function execSimple(command) {
|
|
7
|
+
if (typeof command !== 'string') {
|
|
8
|
+
throw new TypeError('execSimple: command must be a string');
|
|
9
|
+
}
|
|
10
|
+
if (process.env.VERBOSE) {
|
|
11
|
+
console.log(command);
|
|
12
|
+
}
|
|
13
|
+
return await new Promise((resolve, reject) => {
|
|
14
|
+
exec(command, {encoding: 'binary', maxBuffer: 5 * 1024}, (error, stdout, stderr) => {
|
|
15
|
+
if (error) {
|
|
16
|
+
reject(error);
|
|
17
|
+
return;
|
|
18
|
+
}
|
|
19
|
+
if (stderr) {
|
|
20
|
+
reject(error);
|
|
21
|
+
return;
|
|
22
|
+
}
|
|
23
|
+
if (stdout) {
|
|
24
|
+
resolve(stdout.toString('utf8').trim());
|
|
25
|
+
}
|
|
26
|
+
});
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
async function execAsBuffer(command) {
|
|
31
|
+
if (typeof command !== 'string') {
|
|
32
|
+
throw new TypeError('execAsBuffer: command must be a string');
|
|
33
|
+
}
|
|
34
|
+
if (process.env.VERBOSE) {
|
|
35
|
+
console.log(command);
|
|
36
|
+
}
|
|
37
|
+
return await new Promise((resolve, reject) => {
|
|
38
|
+
exec(command, {encoding: 'binary', maxBuffer: 5 * 1024}, (error, stdout, stderr) => {
|
|
39
|
+
if (error) {
|
|
40
|
+
reject(error);
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
if (stderr) {
|
|
44
|
+
reject(error);
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
let stdoutAsBuffer = stdout;
|
|
48
|
+
if (typeof stdoutAsBuffer === 'string' && stdoutAsBuffer.length > 0) {
|
|
49
|
+
// noinspection JSCheckFunctionSignatures
|
|
50
|
+
stdoutAsBuffer = Buffer.from(stdoutAsBuffer, 'binary').slice(0, -1);
|
|
51
|
+
}
|
|
52
|
+
if (stdoutAsBuffer && stdoutAsBuffer.length > 0) {
|
|
53
|
+
resolve(stdoutAsBuffer);
|
|
54
|
+
}
|
|
55
|
+
});
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
function toStringValue(r) {
|
|
60
|
+
if (process.env.VERBOSE) {
|
|
61
|
+
console.log("Printing value", r);
|
|
62
|
+
}
|
|
63
|
+
if (r) {
|
|
64
|
+
if (typeof r === 'string') {
|
|
65
|
+
return r;
|
|
66
|
+
} else if (r.toString) {
|
|
67
|
+
// noinspection JSCheckFunctionSignatures
|
|
68
|
+
return r.toString('utf8');
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
function printStringValue(r) {
|
|
74
|
+
if (process.env.VERBOSE) {
|
|
75
|
+
console.log("Printing value", r);
|
|
76
|
+
}
|
|
77
|
+
if (r) {
|
|
78
|
+
if (typeof r === 'string') {
|
|
79
|
+
console.log(r);
|
|
80
|
+
} else if (r.toString) {
|
|
81
|
+
// noinspection JSCheckFunctionSignatures
|
|
82
|
+
console.log(r.toString('utf8'));
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
*
|
|
89
|
+
* @param result
|
|
90
|
+
* @returns {string|null}
|
|
91
|
+
*/
|
|
92
|
+
function toStringOrNull(result) {
|
|
93
|
+
if (result == null) {
|
|
94
|
+
return null;
|
|
95
|
+
}
|
|
96
|
+
if (process.env.VERBOSE) {
|
|
97
|
+
console.log('result', result);
|
|
98
|
+
}
|
|
99
|
+
if (typeof result === 'string' && result.length > 0) {
|
|
100
|
+
return result;
|
|
101
|
+
}
|
|
102
|
+
if (result.slice && result.toString) {
|
|
103
|
+
// noinspection JSCheckFunctionSignatures
|
|
104
|
+
return result.toString('utf8');
|
|
105
|
+
}
|
|
106
|
+
return null;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
*
|
|
111
|
+
* @param {string} file
|
|
112
|
+
* @param {string} sql
|
|
113
|
+
* @returns {Promise<Buffer[]>}
|
|
114
|
+
*/
|
|
115
|
+
async function doSqliteQuery1(file, sql) {
|
|
116
|
+
if (typeof sql !== 'string') {
|
|
117
|
+
throw new TypeError('doSqliteQuery1: sql must be a string');
|
|
118
|
+
}
|
|
119
|
+
if (typeof file !== 'string') {
|
|
120
|
+
throw new TypeError('doSqliteQuery1: file must be a string');
|
|
121
|
+
}
|
|
122
|
+
if (!fs.existsSync(file)) {
|
|
123
|
+
throw new Error(`doSqliteQuery1: file ${file} does not exist`);
|
|
124
|
+
}
|
|
125
|
+
if (process.env.VERBOSE) {
|
|
126
|
+
console.log(`doSqliteQuery1: file ${file}`);
|
|
127
|
+
console.log(`doSqliteQuery1: sql ${sql}`);
|
|
128
|
+
}
|
|
129
|
+
const sqlite3 = require('sqlite3');
|
|
130
|
+
const db = new sqlite3.Database(file);
|
|
131
|
+
return new Promise((resolve, reject) => {
|
|
132
|
+
db.all(sql, (err, rows) => {
|
|
133
|
+
if (err) {
|
|
134
|
+
if (process.env.VERBOSE) {
|
|
135
|
+
console.log(`doSqliteQuery1: error ${err}`);
|
|
136
|
+
}
|
|
137
|
+
reject(err);
|
|
138
|
+
return;
|
|
139
|
+
}
|
|
140
|
+
const rows1 = rows;
|
|
141
|
+
if (rows1 == null || rows1.length === 0) {
|
|
142
|
+
if (process.env.VERBOSE) {
|
|
143
|
+
console.log(`doSqliteQuery1: no rows`);
|
|
144
|
+
}
|
|
145
|
+
resolve([]);
|
|
146
|
+
return;
|
|
147
|
+
}
|
|
148
|
+
if (Array.isArray(rows1)) {
|
|
149
|
+
if (process.env.VERBOSE) {
|
|
150
|
+
console.log(`doSqliteQuery1: ${rows1.length} rows`);
|
|
151
|
+
}
|
|
152
|
+
// noinspection JSCheckFunctionSignatures
|
|
153
|
+
const buffers = rows1.flatMap(row => Object.values(row)).map(v => Buffer.from(v, 'binary'));
|
|
154
|
+
if (process.env.VERBOSE) {
|
|
155
|
+
console.log(`doSqliteQuery1: ${buffers.length} buffers`);
|
|
156
|
+
}
|
|
157
|
+
resolve(buffers);
|
|
158
|
+
return;
|
|
159
|
+
}
|
|
160
|
+
if (process.env.VERBOSE) {
|
|
161
|
+
console.log(`doSqliteQuery1: rows ${JSON.stringify(rows1)}`);
|
|
162
|
+
}
|
|
163
|
+
resolve([rows1]);
|
|
164
|
+
});
|
|
165
|
+
});
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
module.exports = {
|
|
169
|
+
execSimple: execSimple,
|
|
170
|
+
execAsBuffer: execAsBuffer,
|
|
171
|
+
printStringValue: printStringValue,
|
|
172
|
+
toStringValue,
|
|
173
|
+
toStringOrNull: toStringOrNull,
|
|
174
|
+
doSqliteQuery1
|
|
175
|
+
};
|