@mherod/get-cookie 1.1.3 → 1.1.6

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.
Files changed (5) hide show
  1. package/README.md +31 -0
  2. package/cli.js +89 -0
  3. package/index.js +87 -188
  4. package/package.json +2 -2
  5. package/utils.js +76 -0
package/README.md ADDED
@@ -0,0 +1,31 @@
1
+ # get-cookie
2
+
3
+ ## What is it?
4
+
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.
7
+
8
+ ## Installation
9
+
10
+ To install get-cookie, run the following command:
11
+
12
+ $ npm install @mherod/get-cookie --global
13
+
14
+ ## How do I use it?
15
+
16
+ To use get-cookie, run the following command:
17
+
18
+ $ get-cookie <cookie-name> <domain>
19
+
20
+ For example, to get the value of the `auth` cookie on the `www.example.com` domain, run the following command:
21
+
22
+ $ get-cookie auth www.example.com
23
+
24
+ The output of the command will be the value of the cookie.
25
+
26
+ The library can also be used as a module.
27
+
28
+ ```javascript
29
+ const {getCookie} = require('@mherod/get-cookie');
30
+ getCookie('auth', 'www.example.com').then(console.log);
31
+ ```
package/cli.js ADDED
@@ -0,0 +1,89 @@
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
+ const domain = process.argv[3] ?? '%';
10
+
11
+ if (process.argv.includes('--verbose')) {
12
+ process.env.VERBOSE = "true";
13
+ }
14
+ if (process.argv.includes("--chrome-only")) {
15
+ process.env.CHROME_ONLY = "true";
16
+ }
17
+ if (process.argv.includes("--firefox-only")) {
18
+ process.env.FIREFOX_ONLY = "true";
19
+ }
20
+ if (process.argv.includes("--ignore-expired")) {
21
+ process.env.IGNORE_EXPIRED = "true";
22
+ }
23
+
24
+ if (process.env.VERBOSE) {
25
+ console.log("Verbose mode", process.argv);
26
+ }
27
+
28
+ if (process.env.CHROME_ONLY) {
29
+ if (process.env.VERBOSE) {
30
+ console.log('chrome only');
31
+ }
32
+ getChromeCookie({name, domain})
33
+ .then(cookie => {
34
+ if (cookie && cookie.length > 0) {
35
+ printStringValue(cookie);
36
+ } else {
37
+ console.log('No cookie found');
38
+ }
39
+ })
40
+ .catch(err => {
41
+ if (process.env.VERBOSE) {
42
+ console.error(err);
43
+ }
44
+ });
45
+ } else if (process.env.FIREFOX_ONLY) {
46
+ if (process.env.VERBOSE) {
47
+ console.log('firefox only');
48
+ }
49
+ getFirefoxCookie({name, domain})
50
+ .then(cookie => {
51
+ if (cookie && cookie.length > 0) {
52
+ printStringValue(cookie);
53
+ } else {
54
+ console.log('No cookie found');
55
+ }
56
+ })
57
+ .catch(err => {
58
+ if (process.env.VERBOSE) {
59
+ console.error("Error getting Firefox cookie", err);
60
+ }
61
+ });
62
+ } else {
63
+ getChromeCookie({name, domain})
64
+ .catch(err => {
65
+ if (process.env.VERBOSE) {
66
+ console.error("Error getting Chrome cookie", err);
67
+ }
68
+ })
69
+ .then(r => {
70
+ if (typeof r === 'string' && r.trim().length > 0) {
71
+ return r;
72
+ } else {
73
+ return getFirefoxCookie({name, domain})
74
+ .catch(err => {
75
+ if (process.env.VERBOSE) {
76
+ console.error("Error getting Firefox cookie", err);
77
+ }
78
+ });
79
+ }
80
+ })
81
+ .catch((e) => {
82
+ if (process.env.VERBOSE) {
83
+ console.error("Error getting Chrome or Firefox cookie", e);
84
+ }
85
+ })
86
+ .then(printStringValue);
87
+ }
88
+ }
89
+ }
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} = require("./utils");
6
6
 
7
7
  if (process.platform !== 'darwin') {
8
8
  throw new Error('This script only works on macOS');
@@ -13,23 +13,10 @@ if (process.platform !== 'darwin') {
13
13
  * @returns {Promise<string>}
14
14
  */
15
15
  async function getChromePassword() {
16
- return await new Promise((resolve, reject) => {
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
- async function getCookie() {
19
+ async function getCookie(name, domain) {
33
20
  throw new Error('Not implemented');
34
21
  }
35
22
 
@@ -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 findFile(`${process.env.HOME}/Library/Application Support/Firefox/Profiles`, "cookies.sqlite")
50
- if (!fs.existsSync(file)) {
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) {
@@ -73,7 +63,7 @@ async function getFirefoxCookie({name, domain}) {
73
63
  const defaultChromeRoot = `${process.env.HOME}/Library/Application Support/Google/Chrome`;
74
64
  const defaultChromeCookies = `${defaultChromeRoot}/Default/Cookies`;
75
65
 
76
- async function getEncryptedChromeCookie(name, domain, file = defaultChromeCookies) {
66
+ async function getEncryptedChromeCookie({name, domain, file = defaultChromeCookies}) {
77
67
  if (name && typeof name !== 'string') {
78
68
  throw new Error('name must be a string');
79
69
  }
@@ -134,33 +124,6 @@ async function doSqliteQuery1(file, sql) {
134
124
  });
135
125
  }
136
126
 
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
127
  /**
165
128
  *
166
129
  * @param {string} password
@@ -213,8 +176,8 @@ async function decrypt(password, encryptedData) {
213
176
  return;
214
177
  }
215
178
 
216
- let decoded = decipher.update(encryptedData1, 'binary', 'utf8');
217
- // let decoded = decipher.update(encryptedData);
179
+ // let decoded = decipher.update(encryptedData1, 'binary', 'utf8');
180
+ let decoded = decipher.update(encryptedData);
218
181
  try {
219
182
  decipher.final('utf-8');
220
183
  } catch (e) {
@@ -242,37 +205,75 @@ async function decrypt(password, encryptedData) {
242
205
  /**
243
206
  *
244
207
  * @param {string|undefined} name
245
- * @param {string|undefined} domain
208
+ * @param {string} domain
246
209
  * @returns {Promise<string>}
247
210
  */
248
- async function getChromeCookie({name, domain}) {
211
+ async function getChromeCookie({name, domain = '%'}) {
249
212
  if (name && typeof name !== 'string') {
250
213
  throw new Error('name must be a string');
251
214
  }
252
- if (domain && typeof domain !== 'string') {
215
+ if (typeof domain !== 'string') {
253
216
  throw new Error('domain must be a string');
254
217
  }
255
218
  const chromePasswordPromise = getChromePassword();
256
- const [encryptedData] = await findAllFiles({path: defaultChromeRoot, name: 'Cookies'}).then(files => {
257
- return Promise.all(files.map(file => getEncryptedChromeCookie(name, domain, file)));
219
+ const encryptedDataItems = await findAllFiles({
220
+ path: defaultChromeRoot,
221
+ name: 'Cookies'
222
+ }).then(files => {
223
+ const promises = files.map(file => {
224
+ return getEncryptedChromeCookie({
225
+ name: name,
226
+ domain: domain,
227
+ file: file
228
+ }).catch(e => {
229
+ if (process.env.VERBOSE) {
230
+ console.log("Error getting encrypted cookie", e);
231
+ }
232
+ return null;
233
+ });
234
+ });
235
+ const promise = Promise.all(promises).then(results => {
236
+ return results.filter(result => {
237
+ return result;
238
+ });
239
+ });
240
+ if (process.env.VERBOSE) {
241
+ console.log('promise', promise);
242
+ }
243
+ return promise;
244
+ }).catch(error => {
245
+ if (process.env.VERBOSE) {
246
+ console.log('error', error);
247
+ }
248
+ return [];
258
249
  });
259
250
  const password = await chromePasswordPromise;
260
- if (process.env.VERBOSE) {
261
- console.log("Received encrypted", encryptedData);
262
- }
263
- let s;
264
- try {
265
- s = await decrypt(password, encryptedData);
266
- } catch (e) {
251
+ const decrypted = encryptedDataItems.filter(encryptedData => {
252
+ return encryptedData != null && encryptedData.length > 0;
253
+ }).map(async encryptedData => {
267
254
  if (process.env.VERBOSE) {
268
- console.error("Error decrypting", e);
255
+ console.log("Received encrypted", encryptedData);
269
256
  }
270
- throw new Error('Failed to decrypt');
271
- }
272
- if (process.env.VERBOSE) {
273
- console.log("Decrypted", s);
274
- }
275
- return s;
257
+ let decrypted;
258
+ try {
259
+ decrypted = await decrypt(password, encryptedData);
260
+ } catch (e) {
261
+ if (process.env.VERBOSE) {
262
+ console.log("Error decrypting cookie", e);
263
+ }
264
+ return null;
265
+ }
266
+ if (decrypted) {
267
+ if (process.env.VERBOSE) {
268
+ console.log("Decrypted", decrypted);
269
+ }
270
+ return decrypted;
271
+ }
272
+ return null;
273
+ });
274
+ return await Promise.all(decrypted).then(results => {
275
+ return results.find(result => typeof result === 'string' && result.length > 0);
276
+ });
276
277
  }
277
278
 
278
279
  /**
@@ -294,9 +295,26 @@ async function findAllFiles({path, name, rootSegments = path.split('/').length,
294
295
  console.log(`Searching for ${name} in ${path}`);
295
296
  }
296
297
  const files = [];
297
- for (const file of fs.readdirSync(path)) {
298
+ let readdirSync;
299
+ try {
300
+ readdirSync = fs.readdirSync(path);
301
+ } catch (e) {
302
+ if (process.env.VERBOSE) {
303
+ console.log(`Error reading ${path}`, e);
304
+ }
305
+ return files;
306
+ }
307
+ for (const file of readdirSync) {
298
308
  const filePath = path + '/' + file;
299
- const stat = fs.statSync(filePath);
309
+ let stat;
310
+ try {
311
+ stat = fs.statSync(filePath);
312
+ } catch (e) {
313
+ if (process.env.VERBOSE) {
314
+ console.error(`Error getting stat for ${filePath}`, e);
315
+ }
316
+ continue;
317
+ }
300
318
  if (stat.isDirectory()) {
301
319
  if (filePath.split('/').length < rootSegments + maxDepth) {
302
320
  try {
@@ -326,40 +344,6 @@ async function findAllFiles({path, name, rootSegments = path.split('/').length,
326
344
  return files;
327
345
  }
328
346
 
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
347
  // noinspection JSUnusedGlobalSymbols
364
348
  module.exports = {
365
349
  getDecryptedCookie: getChromeCookie,
@@ -367,88 +351,3 @@ module.exports = {
367
351
  getFirefoxCookie,
368
352
  getCookie
369
353
  };
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,9 +1,9 @@
1
1
  {
2
2
  "name": "@mherod/get-cookie",
3
- "version": "1.1.3",
3
+ "version": "1.1.6",
4
4
  "description": "Node.js module for querying a local user's Chrome cookie",
5
5
  "main": "index.js",
6
- "bin": "index.js",
6
+ "bin": "cli.js",
7
7
  "publishConfig": {
8
8
  "access": "public"
9
9
  },
package/utils.js ADDED
@@ -0,0 +1,76 @@
1
+ // noinspection JSUnusedGlobalSymbols
2
+
3
+ const {exec} = require('child_process');
4
+
5
+ async function execSimple(command) {
6
+ if (typeof command !== 'string') {
7
+ throw new TypeError('execSimple: command must be a string');
8
+ }
9
+ if (process.env.VERBOSE) {
10
+ console.log(command);
11
+ }
12
+ return await new Promise((resolve, reject) => {
13
+ exec(command, {encoding: 'binary', maxBuffer: 5 * 1024}, (error, stdout, stderr) => {
14
+ if (error) {
15
+ reject(error);
16
+ return;
17
+ }
18
+ if (stderr) {
19
+ reject(error);
20
+ return;
21
+ }
22
+ if (stdout) {
23
+ resolve(stdout.toString('utf8').trim());
24
+ }
25
+ });
26
+ });
27
+ }
28
+
29
+ async function execAsBuffer(command) {
30
+ if (typeof command !== 'string') {
31
+ throw new TypeError('execAsBuffer: command must be a string');
32
+ }
33
+ if (process.env.VERBOSE) {
34
+ console.log(command);
35
+ }
36
+ return await new Promise((resolve, reject) => {
37
+ exec(command, {encoding: 'binary', maxBuffer: 5 * 1024}, (error, stdout, stderr) => {
38
+ if (error) {
39
+ reject(error);
40
+ return;
41
+ }
42
+ if (stderr) {
43
+ reject(error);
44
+ return;
45
+ }
46
+ let stdoutAsBuffer = stdout;
47
+ if (typeof stdoutAsBuffer === 'string' && stdoutAsBuffer.length > 0) {
48
+ // noinspection JSCheckFunctionSignatures
49
+ stdoutAsBuffer = Buffer.from(stdoutAsBuffer, 'binary').slice(0, -1);
50
+ }
51
+ if (stdoutAsBuffer && stdoutAsBuffer.length > 0) {
52
+ resolve(stdoutAsBuffer);
53
+ }
54
+ });
55
+ });
56
+ }
57
+
58
+ function printStringValue(r) {
59
+ if (process.env.VERBOSE) {
60
+ console.log("Printing value", r);
61
+ }
62
+ if (r) {
63
+ if (typeof r === 'string') {
64
+ console.log(r);
65
+ } else if (r.toString) {
66
+ // noinspection JSCheckFunctionSignatures
67
+ console.log(r.toString('utf8'));
68
+ }
69
+ }
70
+ }
71
+
72
+ module.exports = {
73
+ execSimple: execSimple,
74
+ execAsBuffer: execAsBuffer,
75
+ printStringValue: printStringValue
76
+ };