@mherod/get-cookie 1.1.4 → 1.1.7
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 +7 -6
- package/cli.js +95 -0
- package/index.js +109 -219
- package/package.json +6 -3
- package/utils.js +160 -0
package/README.md
CHANGED
|
@@ -2,27 +2,28 @@
|
|
|
2
2
|
|
|
3
3
|
## What is it?
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
get-cookie is a command line utility that allows you to get the value of a cookie from your locally installed browser.
|
|
6
|
+
It is useful for testing web pages that require authentication.
|
|
6
7
|
|
|
7
8
|
## Installation
|
|
8
9
|
|
|
9
|
-
|
|
10
|
+
To install get-cookie, run the following command:
|
|
10
11
|
|
|
11
12
|
$ npm install @mherod/get-cookie --global
|
|
12
13
|
|
|
13
14
|
## How do I use it?
|
|
14
15
|
|
|
15
|
-
|
|
16
|
+
To use get-cookie, run the following command:
|
|
16
17
|
|
|
17
18
|
$ get-cookie <cookie-name> <domain>
|
|
18
19
|
|
|
19
|
-
|
|
20
|
+
For example, to get the value of the `auth` cookie on the `www.example.com` domain, run the following command:
|
|
20
21
|
|
|
21
22
|
$ get-cookie auth www.example.com
|
|
22
23
|
|
|
23
|
-
|
|
24
|
+
The output of the command will be the value of the cookie.
|
|
24
25
|
|
|
25
|
-
|
|
26
|
+
The library can also be used as a module.
|
|
26
27
|
|
|
27
28
|
```javascript
|
|
28
29
|
const {getCookie} = require('@mherod/get-cookie');
|
package/cli.js
ADDED
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
const {getFirefoxCookie, getChromeCookie} = require("./index");
|
|
4
|
+
const {printStringValue} = require("./utils");
|
|
5
|
+
|
|
6
|
+
if (process.argv) {
|
|
7
|
+
if (process.argv.length > 2) {
|
|
8
|
+
const name = process.argv[2];
|
|
9
|
+
|
|
10
|
+
let domain;
|
|
11
|
+
if (process.argv[3] != null && process.argv[3].indexOf(".") > -1) {
|
|
12
|
+
domain = process.argv[3];
|
|
13
|
+
} else {
|
|
14
|
+
domain = '%';
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
if (process.argv.includes('--verbose')) {
|
|
18
|
+
process.env.VERBOSE = "true";
|
|
19
|
+
}
|
|
20
|
+
if (process.argv.includes("--chrome-only")) {
|
|
21
|
+
process.env.CHROME_ONLY = "true";
|
|
22
|
+
}
|
|
23
|
+
if (process.argv.includes("--firefox-only")) {
|
|
24
|
+
process.env.FIREFOX_ONLY = "true";
|
|
25
|
+
}
|
|
26
|
+
if (process.argv.includes("--ignore-expired")) {
|
|
27
|
+
process.env.IGNORE_EXPIRED = "true";
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
if (process.env.VERBOSE) {
|
|
31
|
+
console.log("Verbose mode", process.argv);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
if (process.env.CHROME_ONLY) {
|
|
35
|
+
if (process.env.VERBOSE) {
|
|
36
|
+
console.log('chrome only');
|
|
37
|
+
}
|
|
38
|
+
getChromeCookie({name, domain})
|
|
39
|
+
.then(cookie => {
|
|
40
|
+
if (cookie && cookie.length > 0) {
|
|
41
|
+
printStringValue(cookie);
|
|
42
|
+
} else {
|
|
43
|
+
console.log('No cookie found');
|
|
44
|
+
}
|
|
45
|
+
})
|
|
46
|
+
.catch(err => {
|
|
47
|
+
if (process.env.VERBOSE) {
|
|
48
|
+
console.error(err);
|
|
49
|
+
}
|
|
50
|
+
});
|
|
51
|
+
} else if (process.env.FIREFOX_ONLY) {
|
|
52
|
+
if (process.env.VERBOSE) {
|
|
53
|
+
console.log('firefox only');
|
|
54
|
+
}
|
|
55
|
+
getFirefoxCookie({name, domain})
|
|
56
|
+
.then(cookie => {
|
|
57
|
+
if (cookie && cookie.length > 0) {
|
|
58
|
+
printStringValue(cookie);
|
|
59
|
+
} else {
|
|
60
|
+
console.log('No cookie found');
|
|
61
|
+
}
|
|
62
|
+
})
|
|
63
|
+
.catch(err => {
|
|
64
|
+
if (process.env.VERBOSE) {
|
|
65
|
+
console.error("Error getting Firefox cookie", err);
|
|
66
|
+
}
|
|
67
|
+
});
|
|
68
|
+
} else {
|
|
69
|
+
getChromeCookie({name, domain})
|
|
70
|
+
.catch(err => {
|
|
71
|
+
if (process.env.VERBOSE) {
|
|
72
|
+
console.error("Error getting Chrome cookie", err);
|
|
73
|
+
}
|
|
74
|
+
})
|
|
75
|
+
.then(r => {
|
|
76
|
+
if (typeof r === 'string' && r.trim().length > 0) {
|
|
77
|
+
return r;
|
|
78
|
+
} else {
|
|
79
|
+
return getFirefoxCookie({name, domain})
|
|
80
|
+
.catch(err => {
|
|
81
|
+
if (process.env.VERBOSE) {
|
|
82
|
+
console.error("Error getting Firefox cookie", err);
|
|
83
|
+
}
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
})
|
|
87
|
+
.catch((e) => {
|
|
88
|
+
if (process.env.VERBOSE) {
|
|
89
|
+
console.error("Error getting Chrome or Firefox cookie", e);
|
|
90
|
+
}
|
|
91
|
+
})
|
|
92
|
+
.then(printStringValue);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
}
|
package/index.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
const crypto = require('crypto');
|
|
4
|
-
const {exec} = require("child_process");
|
|
5
4
|
const fs = require("fs");
|
|
5
|
+
const {execSimple, toStringOrNull, doSqliteQuery1} = require("./utils");
|
|
6
6
|
|
|
7
7
|
if (process.platform !== 'darwin') {
|
|
8
8
|
throw new Error('This script only works on macOS');
|
|
@@ -13,20 +13,7 @@ if (process.platform !== 'darwin') {
|
|
|
13
13
|
* @returns {Promise<string>}
|
|
14
14
|
*/
|
|
15
15
|
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
|
-
});
|
|
16
|
+
return await execSimple("security find-generic-password -w -s \"Chrome Safe Storage\"");
|
|
30
17
|
}
|
|
31
18
|
|
|
32
19
|
async function getCookie(name, domain) {
|
|
@@ -46,8 +33,11 @@ async function getFirefoxCookie({name, domain}) {
|
|
|
46
33
|
if (domain && typeof domain !== 'string') {
|
|
47
34
|
throw new Error('domain must be a string');
|
|
48
35
|
}
|
|
49
|
-
const file = await
|
|
50
|
-
|
|
36
|
+
const [file] = await findAllFiles({
|
|
37
|
+
path: `${process.env.HOME}/Library/Application Support/Firefox/Profiles`,
|
|
38
|
+
name: "cookies.sqlite"
|
|
39
|
+
})
|
|
40
|
+
if (file && !fs.existsSync(file)) {
|
|
51
41
|
throw new Error(`File ${file} does not exist`);
|
|
52
42
|
}
|
|
53
43
|
if (process.env.VERBOSE) {
|
|
@@ -67,13 +57,15 @@ async function getFirefoxCookie({name, domain}) {
|
|
|
67
57
|
sql += `host LIKE '${domain}';`;
|
|
68
58
|
}
|
|
69
59
|
}
|
|
70
|
-
return await doSqliteQuery1(file, sql)
|
|
60
|
+
return await doSqliteQuery1(file, sql).then(rows => {
|
|
61
|
+
return rows.map(toStringOrNull).find(v => v !== null);
|
|
62
|
+
});
|
|
71
63
|
}
|
|
72
64
|
|
|
73
65
|
const defaultChromeRoot = `${process.env.HOME}/Library/Application Support/Google/Chrome`;
|
|
74
66
|
const defaultChromeCookies = `${defaultChromeRoot}/Default/Cookies`;
|
|
75
67
|
|
|
76
|
-
async function getEncryptedChromeCookie(name, domain, file = defaultChromeCookies) {
|
|
68
|
+
async function getEncryptedChromeCookie({name, domain, file = defaultChromeCookies}) {
|
|
77
69
|
if (name && typeof name !== 'string') {
|
|
78
70
|
throw new Error('name must be a string');
|
|
79
71
|
}
|
|
@@ -87,7 +79,7 @@ async function getEncryptedChromeCookie(name, domain, file = defaultChromeCookie
|
|
|
87
79
|
throw new Error(`File ${file} does not exist`);
|
|
88
80
|
}
|
|
89
81
|
if (process.env.VERBOSE) {
|
|
90
|
-
console.log(`Trying Chrome (at ${file}) cookie ${name} for domain ${domain}`);
|
|
82
|
+
console.log(`Trying Chrome (at ${file.split('/').slice(-3).join('/')}) cookie ${name} for domain ${domain}`);
|
|
91
83
|
}
|
|
92
84
|
let sql;
|
|
93
85
|
sql = `SELECT encrypted_value FROM cookies`;
|
|
@@ -106,75 +98,32 @@ async function getEncryptedChromeCookie(name, domain, file = defaultChromeCookie
|
|
|
106
98
|
return await doSqliteQuery1(file, sql);
|
|
107
99
|
}
|
|
108
100
|
|
|
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
101
|
/**
|
|
165
102
|
*
|
|
166
103
|
* @param {string} password
|
|
167
|
-
* @param encryptedData
|
|
104
|
+
* @param {Buffer} encryptedData
|
|
168
105
|
* @returns {Promise<string>}
|
|
169
106
|
*/
|
|
170
107
|
async function decrypt(password, encryptedData) {
|
|
171
108
|
if (typeof password !== 'string') {
|
|
172
109
|
throw new Error('password must be a string: ' + password);
|
|
173
110
|
}
|
|
174
|
-
|
|
111
|
+
let encryptedData1;
|
|
112
|
+
encryptedData1 = encryptedData;
|
|
175
113
|
if (encryptedData1 == null || typeof encryptedData1 !== 'object') {
|
|
176
114
|
throw new Error('encryptedData must be a object: ' + encryptedData1);
|
|
177
115
|
}
|
|
116
|
+
if (!(encryptedData1 instanceof Buffer)) {
|
|
117
|
+
if (Array.isArray(encryptedData1) && encryptedData1[0] instanceof Buffer) {
|
|
118
|
+
[encryptedData1] = encryptedData1;
|
|
119
|
+
if (process.env.VERBOSE) {
|
|
120
|
+
console.log(`encryptedData is an array of buffers, selected first: ${encryptedData1}`);
|
|
121
|
+
}
|
|
122
|
+
} else {
|
|
123
|
+
throw new Error('encryptedData must be a Buffer: ' + encryptedData1);
|
|
124
|
+
}
|
|
125
|
+
encryptedData1 = Buffer.from(encryptedData1);
|
|
126
|
+
}
|
|
178
127
|
if (process.env.VERBOSE) {
|
|
179
128
|
console.log(`Trying to decrypt with password ${password}`);
|
|
180
129
|
}
|
|
@@ -202,7 +151,7 @@ async function decrypt(password, encryptedData) {
|
|
|
202
151
|
decipher.setAutoPadding(false);
|
|
203
152
|
|
|
204
153
|
if (encryptedData1 && encryptedData1.slice) {
|
|
205
|
-
|
|
154
|
+
encryptedData1 = encryptedData1.slice(3);
|
|
206
155
|
}
|
|
207
156
|
|
|
208
157
|
if (encryptedData1.length % 16 !== 0) {
|
|
@@ -213,8 +162,7 @@ async function decrypt(password, encryptedData) {
|
|
|
213
162
|
return;
|
|
214
163
|
}
|
|
215
164
|
|
|
216
|
-
let decoded = decipher.update(encryptedData1
|
|
217
|
-
// let decoded = decipher.update(encryptedData);
|
|
165
|
+
let decoded = decipher.update(encryptedData1);
|
|
218
166
|
try {
|
|
219
167
|
decipher.final('utf-8');
|
|
220
168
|
} catch (e) {
|
|
@@ -242,37 +190,80 @@ async function decrypt(password, encryptedData) {
|
|
|
242
190
|
/**
|
|
243
191
|
*
|
|
244
192
|
* @param {string|undefined} name
|
|
245
|
-
* @param {string
|
|
193
|
+
* @param {string} domain
|
|
246
194
|
* @returns {Promise<string>}
|
|
247
195
|
*/
|
|
248
|
-
async function getChromeCookie({name, domain}) {
|
|
196
|
+
async function getChromeCookie({name, domain = '%'}) {
|
|
249
197
|
if (name && typeof name !== 'string') {
|
|
250
198
|
throw new Error('name must be a string');
|
|
251
199
|
}
|
|
252
|
-
if (
|
|
200
|
+
if (typeof domain !== 'string') {
|
|
253
201
|
throw new Error('domain must be a string');
|
|
254
202
|
}
|
|
255
|
-
const
|
|
256
|
-
|
|
257
|
-
|
|
203
|
+
const encryptedDataItems = await findAllFiles({
|
|
204
|
+
path: defaultChromeRoot,
|
|
205
|
+
name: 'Cookies'
|
|
206
|
+
}).then(files => {
|
|
207
|
+
const promises = files.map(file => {
|
|
208
|
+
return getEncryptedChromeCookie({
|
|
209
|
+
name: name,
|
|
210
|
+
domain: domain,
|
|
211
|
+
file: file
|
|
212
|
+
}).catch(e => {
|
|
213
|
+
if (process.env.VERBOSE) {
|
|
214
|
+
console.log("Error getting encrypted cookie", e);
|
|
215
|
+
}
|
|
216
|
+
return [];
|
|
217
|
+
});
|
|
218
|
+
});
|
|
219
|
+
return Promise.all(promises).then(results => results.flat()).then(results => {
|
|
220
|
+
if (process.env.VERBOSE) {
|
|
221
|
+
console.log("getEncryptedChromeCookie results", results);
|
|
222
|
+
}
|
|
223
|
+
return results.filter(result => {
|
|
224
|
+
return result;
|
|
225
|
+
});
|
|
226
|
+
});
|
|
227
|
+
}).catch(error => {
|
|
228
|
+
if (process.env.VERBOSE) {
|
|
229
|
+
console.log('error', error);
|
|
230
|
+
}
|
|
231
|
+
return [];
|
|
258
232
|
});
|
|
259
|
-
const password = await
|
|
233
|
+
const password = await getChromePassword();
|
|
260
234
|
if (process.env.VERBOSE) {
|
|
261
|
-
console.log(
|
|
235
|
+
console.log('encryptedDataItems', encryptedDataItems);
|
|
262
236
|
}
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
} catch (e) {
|
|
237
|
+
const decrypted = encryptedDataItems.filter(encryptedData => {
|
|
238
|
+
return encryptedData != null && encryptedData.length > 0;
|
|
239
|
+
}).map(async encryptedData => {
|
|
267
240
|
if (process.env.VERBOSE) {
|
|
268
|
-
console.
|
|
241
|
+
console.log("Received encrypted", encryptedData);
|
|
269
242
|
}
|
|
270
|
-
|
|
271
|
-
|
|
243
|
+
let decrypted;
|
|
244
|
+
try {
|
|
245
|
+
decrypted = await decrypt(password, encryptedData);
|
|
246
|
+
} catch (e) {
|
|
247
|
+
if (process.env.VERBOSE) {
|
|
248
|
+
console.log("Error decrypting cookie", e);
|
|
249
|
+
}
|
|
250
|
+
return null;
|
|
251
|
+
}
|
|
252
|
+
if (decrypted) {
|
|
253
|
+
if (process.env.VERBOSE) {
|
|
254
|
+
console.log("Decrypted", decrypted);
|
|
255
|
+
}
|
|
256
|
+
return decrypted;
|
|
257
|
+
}
|
|
258
|
+
return null;
|
|
259
|
+
});
|
|
260
|
+
const results = await Promise.all(decrypted);
|
|
272
261
|
if (process.env.VERBOSE) {
|
|
273
|
-
console.log(
|
|
262
|
+
console.log('results', results);
|
|
274
263
|
}
|
|
275
|
-
return
|
|
264
|
+
return results.map(toStringOrNull).find(result => {
|
|
265
|
+
return typeof result === 'string' && result.length > 0;
|
|
266
|
+
});
|
|
276
267
|
}
|
|
277
268
|
|
|
278
269
|
/**
|
|
@@ -294,9 +285,26 @@ async function findAllFiles({path, name, rootSegments = path.split('/').length,
|
|
|
294
285
|
console.log(`Searching for ${name} in ${path}`);
|
|
295
286
|
}
|
|
296
287
|
const files = [];
|
|
297
|
-
|
|
288
|
+
let readdirSync;
|
|
289
|
+
try {
|
|
290
|
+
readdirSync = fs.readdirSync(path);
|
|
291
|
+
} catch (e) {
|
|
292
|
+
if (process.env.VERBOSE) {
|
|
293
|
+
console.log(`Error reading ${path}`, e);
|
|
294
|
+
}
|
|
295
|
+
return files;
|
|
296
|
+
}
|
|
297
|
+
for (const file of readdirSync) {
|
|
298
298
|
const filePath = path + '/' + file;
|
|
299
|
-
|
|
299
|
+
let stat;
|
|
300
|
+
try {
|
|
301
|
+
stat = fs.statSync(filePath);
|
|
302
|
+
} catch (e) {
|
|
303
|
+
if (process.env.VERBOSE) {
|
|
304
|
+
console.error(`Error getting stat for ${filePath}`, e);
|
|
305
|
+
}
|
|
306
|
+
continue;
|
|
307
|
+
}
|
|
300
308
|
if (stat.isDirectory()) {
|
|
301
309
|
if (filePath.split('/').length < rootSegments + maxDepth) {
|
|
302
310
|
try {
|
|
@@ -326,129 +334,11 @@ async function findAllFiles({path, name, rootSegments = path.split('/').length,
|
|
|
326
334
|
return files;
|
|
327
335
|
}
|
|
328
336
|
|
|
329
|
-
/**
|
|
330
|
-
*
|
|
331
|
-
* @param path
|
|
332
|
-
* @param name
|
|
333
|
-
* @returns {Promise<string>}
|
|
334
|
-
*/
|
|
335
|
-
async function findFile(path, name) {
|
|
336
|
-
return await new Promise((resolve, reject) => {
|
|
337
|
-
for (const file of fs.readdirSync(path)) {
|
|
338
|
-
const filePath = path + '/' + file;
|
|
339
|
-
const stat = fs.statSync(filePath);
|
|
340
|
-
if (stat.isDirectory()) {
|
|
341
|
-
findFile(filePath, name).then(resolve).catch(reject);
|
|
342
|
-
} else if (file === name) {
|
|
343
|
-
resolve(filePath);
|
|
344
|
-
}
|
|
345
|
-
}
|
|
346
|
-
});
|
|
347
|
-
}
|
|
348
|
-
|
|
349
|
-
function printStringValue(r) {
|
|
350
|
-
if (process.env.VERBOSE) {
|
|
351
|
-
console.log("Printing value", r);
|
|
352
|
-
}
|
|
353
|
-
if (r) {
|
|
354
|
-
if (typeof r === 'string') {
|
|
355
|
-
console.log(r);
|
|
356
|
-
} else if (r.toString) {
|
|
357
|
-
// noinspection JSCheckFunctionSignatures
|
|
358
|
-
console.log(r.toString('utf8'));
|
|
359
|
-
}
|
|
360
|
-
}
|
|
361
|
-
}
|
|
362
|
-
|
|
363
337
|
// noinspection JSUnusedGlobalSymbols
|
|
364
338
|
module.exports = {
|
|
365
339
|
getDecryptedCookie: getChromeCookie,
|
|
366
340
|
getChromeCookie,
|
|
367
341
|
getFirefoxCookie,
|
|
368
|
-
getCookie
|
|
342
|
+
getCookie,
|
|
343
|
+
decrypt
|
|
369
344
|
};
|
|
370
|
-
|
|
371
|
-
if (process.argv) {
|
|
372
|
-
if (process.argv.length > 2) {
|
|
373
|
-
const name = process.argv[2];
|
|
374
|
-
const domain = process.argv[3] ?? '%';
|
|
375
|
-
|
|
376
|
-
if (process.argv.includes('--verbose')) {
|
|
377
|
-
process.env.VERBOSE = "true";
|
|
378
|
-
}
|
|
379
|
-
if (process.argv.includes("--chrome-only")) {
|
|
380
|
-
process.env.CHROME_ONLY = "true";
|
|
381
|
-
}
|
|
382
|
-
if (process.argv.includes("--firefox-only")) {
|
|
383
|
-
process.env.FIREFOX_ONLY = "true";
|
|
384
|
-
}
|
|
385
|
-
if (process.argv.includes("--ignore-expired")) {
|
|
386
|
-
process.env.IGNORE_EXPIRED = "true";
|
|
387
|
-
}
|
|
388
|
-
|
|
389
|
-
if (process.env.VERBOSE) {
|
|
390
|
-
console.log("Verbose mode", process.argv);
|
|
391
|
-
}
|
|
392
|
-
|
|
393
|
-
if (process.env.CHROME_ONLY) {
|
|
394
|
-
if (process.env.VERBOSE) {
|
|
395
|
-
console.log('chrome only');
|
|
396
|
-
}
|
|
397
|
-
getChromeCookie({name, domain})
|
|
398
|
-
.then(cookie => {
|
|
399
|
-
if (cookie && cookie.length > 0) {
|
|
400
|
-
printStringValue(cookie);
|
|
401
|
-
} else {
|
|
402
|
-
console.log('No cookie found');
|
|
403
|
-
}
|
|
404
|
-
})
|
|
405
|
-
.catch(err => {
|
|
406
|
-
if (process.env.VERBOSE) {
|
|
407
|
-
console.error(err);
|
|
408
|
-
}
|
|
409
|
-
});
|
|
410
|
-
} else if (process.env.FIREFOX_ONLY) {
|
|
411
|
-
if (process.env.VERBOSE) {
|
|
412
|
-
console.log('firefox only');
|
|
413
|
-
}
|
|
414
|
-
getFirefoxCookie({name, domain})
|
|
415
|
-
.then(cookie => {
|
|
416
|
-
if (cookie && cookie.length > 0) {
|
|
417
|
-
printStringValue(cookie);
|
|
418
|
-
} else {
|
|
419
|
-
console.log('No cookie found');
|
|
420
|
-
}
|
|
421
|
-
})
|
|
422
|
-
.catch(err => {
|
|
423
|
-
if (process.env.VERBOSE) {
|
|
424
|
-
console.error("Error getting Firefox cookie", err);
|
|
425
|
-
}
|
|
426
|
-
});
|
|
427
|
-
} else {
|
|
428
|
-
getChromeCookie({name, domain})
|
|
429
|
-
.catch(err => {
|
|
430
|
-
if (process.env.VERBOSE) {
|
|
431
|
-
console.error("Error getting Chrome cookie", err);
|
|
432
|
-
}
|
|
433
|
-
})
|
|
434
|
-
.then(r => {
|
|
435
|
-
if (typeof r === 'string' && r.trim().length > 0) {
|
|
436
|
-
return r;
|
|
437
|
-
} else {
|
|
438
|
-
return getFirefoxCookie({name, domain})
|
|
439
|
-
.catch(err => {
|
|
440
|
-
if (process.env.VERBOSE) {
|
|
441
|
-
console.error("Error getting Firefox cookie", err);
|
|
442
|
-
}
|
|
443
|
-
});
|
|
444
|
-
}
|
|
445
|
-
})
|
|
446
|
-
.catch((e) => {
|
|
447
|
-
if (process.env.VERBOSE) {
|
|
448
|
-
console.error("Error getting Chrome or Firefox cookie", e);
|
|
449
|
-
}
|
|
450
|
-
})
|
|
451
|
-
.then(printStringValue);
|
|
452
|
-
}
|
|
453
|
-
}
|
|
454
|
-
}
|
package/package.json
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mherod/get-cookie",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.7",
|
|
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": [],
|
|
@@ -16,5 +16,8 @@
|
|
|
16
16
|
"license": "ISC",
|
|
17
17
|
"dependencies": {
|
|
18
18
|
"sqlite3": "^5.0.8"
|
|
19
|
+
},
|
|
20
|
+
"devDependencies": {
|
|
21
|
+
"jest": "^28.1.0"
|
|
19
22
|
}
|
|
20
23
|
}
|
package/utils.js
ADDED
|
@@ -0,0 +1,160 @@
|
|
|
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 printStringValue(r) {
|
|
60
|
+
if (process.env.VERBOSE) {
|
|
61
|
+
console.log("Printing value", r);
|
|
62
|
+
}
|
|
63
|
+
if (r) {
|
|
64
|
+
if (typeof r === 'string') {
|
|
65
|
+
console.log(r);
|
|
66
|
+
} else if (r.toString) {
|
|
67
|
+
// noinspection JSCheckFunctionSignatures
|
|
68
|
+
console.log(r.toString('utf8'));
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
*
|
|
75
|
+
* @param result
|
|
76
|
+
* @returns {string|null}
|
|
77
|
+
*/
|
|
78
|
+
function toStringOrNull(result) {
|
|
79
|
+
if (result == null) {
|
|
80
|
+
return null;
|
|
81
|
+
}
|
|
82
|
+
if (process.env.VERBOSE) {
|
|
83
|
+
console.log('result', result);
|
|
84
|
+
}
|
|
85
|
+
if (typeof result === 'string' && result.length > 0) {
|
|
86
|
+
return result;
|
|
87
|
+
}
|
|
88
|
+
if (result.slice && result.toString) {
|
|
89
|
+
// noinspection JSCheckFunctionSignatures
|
|
90
|
+
return result.toString('utf8');
|
|
91
|
+
}
|
|
92
|
+
return null;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
*
|
|
97
|
+
* @param {string} file
|
|
98
|
+
* @param {string} sql
|
|
99
|
+
* @returns {Promise<Buffer[]>}
|
|
100
|
+
*/
|
|
101
|
+
async function doSqliteQuery1(file, sql) {
|
|
102
|
+
if (typeof sql !== 'string') {
|
|
103
|
+
throw new TypeError('doSqliteQuery1: sql must be a string');
|
|
104
|
+
}
|
|
105
|
+
if (typeof file !== 'string') {
|
|
106
|
+
throw new TypeError('doSqliteQuery1: file must be a string');
|
|
107
|
+
}
|
|
108
|
+
if (!fs.existsSync(file)) {
|
|
109
|
+
throw new Error(`doSqliteQuery1: file ${file} does not exist`);
|
|
110
|
+
}
|
|
111
|
+
if (process.env.VERBOSE) {
|
|
112
|
+
console.log(`doSqliteQuery1: file ${file}`);
|
|
113
|
+
console.log(`doSqliteQuery1: sql ${sql}`);
|
|
114
|
+
}
|
|
115
|
+
const sqlite3 = require('sqlite3');
|
|
116
|
+
const db = new sqlite3.Database(file);
|
|
117
|
+
return new Promise((resolve, reject) => {
|
|
118
|
+
db.all(sql, (err, rows) => {
|
|
119
|
+
if (err) {
|
|
120
|
+
if (process.env.VERBOSE) {
|
|
121
|
+
console.log(`doSqliteQuery1: error ${err}`);
|
|
122
|
+
}
|
|
123
|
+
reject(err);
|
|
124
|
+
return;
|
|
125
|
+
}
|
|
126
|
+
const rows1 = rows;
|
|
127
|
+
if (rows1 == null || rows1.length === 0) {
|
|
128
|
+
if (process.env.VERBOSE) {
|
|
129
|
+
console.log(`doSqliteQuery1: no rows`);
|
|
130
|
+
}
|
|
131
|
+
resolve([]);
|
|
132
|
+
return;
|
|
133
|
+
}
|
|
134
|
+
if (Array.isArray(rows1)) {
|
|
135
|
+
if (process.env.VERBOSE) {
|
|
136
|
+
console.log(`doSqliteQuery1: ${rows1.length} rows`);
|
|
137
|
+
}
|
|
138
|
+
// noinspection JSCheckFunctionSignatures
|
|
139
|
+
const buffers = rows1.flatMap(row => Object.values(row)).map(v => Buffer.from(v, 'binary'));
|
|
140
|
+
if (process.env.VERBOSE) {
|
|
141
|
+
console.log(`doSqliteQuery1: ${buffers.length} buffers`);
|
|
142
|
+
}
|
|
143
|
+
resolve(buffers);
|
|
144
|
+
return;
|
|
145
|
+
}
|
|
146
|
+
if (process.env.VERBOSE) {
|
|
147
|
+
console.log(`doSqliteQuery1: rows ${JSON.stringify(rows1)}`);
|
|
148
|
+
}
|
|
149
|
+
resolve([rows1]);
|
|
150
|
+
});
|
|
151
|
+
});
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
module.exports = {
|
|
155
|
+
execSimple: execSimple,
|
|
156
|
+
execAsBuffer: execAsBuffer,
|
|
157
|
+
printStringValue: printStringValue,
|
|
158
|
+
toStringOrNull: toStringOrNull,
|
|
159
|
+
doSqliteQuery1
|
|
160
|
+
};
|