@mherod/get-cookie 1.1.6 → 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.
Files changed (4) hide show
  1. package/cli.js +7 -1
  2. package/index.js +38 -47
  3. package/package.json +5 -2
  4. package/utils.js +85 -1
package/cli.js CHANGED
@@ -6,7 +6,13 @@ const {printStringValue} = require("./utils");
6
6
  if (process.argv) {
7
7
  if (process.argv.length > 2) {
8
8
  const name = process.argv[2];
9
- const domain = process.argv[3] ?? '%';
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
+ }
10
16
 
11
17
  if (process.argv.includes('--verbose')) {
12
18
  process.env.VERBOSE = "true";
package/index.js CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  const crypto = require('crypto');
4
4
  const fs = require("fs");
5
- const {execSimple} = require("./utils");
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');
@@ -57,7 +57,9 @@ async function getFirefoxCookie({name, domain}) {
57
57
  sql += `host LIKE '${domain}';`;
58
58
  }
59
59
  }
60
- return await doSqliteQuery1(file, sql);
60
+ return await doSqliteQuery1(file, sql).then(rows => {
61
+ return rows.map(toStringOrNull).find(v => v !== null);
62
+ });
61
63
  }
62
64
 
63
65
  const defaultChromeRoot = `${process.env.HOME}/Library/Application Support/Google/Chrome`;
@@ -77,7 +79,7 @@ async function getEncryptedChromeCookie({name, domain, file = defaultChromeCooki
77
79
  throw new Error(`File ${file} does not exist`);
78
80
  }
79
81
  if (process.env.VERBOSE) {
80
- 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}`);
81
83
  }
82
84
  let sql;
83
85
  sql = `SELECT encrypted_value FROM cookies`;
@@ -96,48 +98,32 @@ async function getEncryptedChromeCookie({name, domain, file = defaultChromeCooki
96
98
  return await doSqliteQuery1(file, sql);
97
99
  }
98
100
 
99
- async function doSqliteQuery1(file, sql) {
100
- const sqlite3 = require('sqlite3');
101
- const db = new sqlite3.Database(file);
102
- return new Promise((resolve, reject) => {
103
- db.all(sql, (err, rows) => {
104
- if (err) {
105
- reject(err);
106
- return;
107
- }
108
- const rows1 = rows;
109
- if (rows1.length === 0) {
110
- if (process.env.VERBOSE) {
111
- console.log(`No rows found`);
112
- }
113
- resolve(null);
114
- return;
115
- }
116
- if (Array.isArray(rows1)) {
117
- // noinspection JSCheckFunctionSignatures
118
- const [value] = rows1.flatMap(row => Object.values(row));
119
- resolve(Buffer.from(value));
120
- return;
121
- }
122
- resolve(rows1);
123
- });
124
- });
125
- }
126
-
127
101
  /**
128
102
  *
129
103
  * @param {string} password
130
- * @param encryptedData
104
+ * @param {Buffer} encryptedData
131
105
  * @returns {Promise<string>}
132
106
  */
133
107
  async function decrypt(password, encryptedData) {
134
108
  if (typeof password !== 'string') {
135
109
  throw new Error('password must be a string: ' + password);
136
110
  }
137
- const encryptedData1 = encryptedData;
111
+ let encryptedData1;
112
+ encryptedData1 = encryptedData;
138
113
  if (encryptedData1 == null || typeof encryptedData1 !== 'object') {
139
114
  throw new Error('encryptedData must be a object: ' + encryptedData1);
140
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
+ }
141
127
  if (process.env.VERBOSE) {
142
128
  console.log(`Trying to decrypt with password ${password}`);
143
129
  }
@@ -165,7 +151,7 @@ async function decrypt(password, encryptedData) {
165
151
  decipher.setAutoPadding(false);
166
152
 
167
153
  if (encryptedData1 && encryptedData1.slice) {
168
- encryptedData = encryptedData1.slice(3);
154
+ encryptedData1 = encryptedData1.slice(3);
169
155
  }
170
156
 
171
157
  if (encryptedData1.length % 16 !== 0) {
@@ -176,8 +162,7 @@ async function decrypt(password, encryptedData) {
176
162
  return;
177
163
  }
178
164
 
179
- // let decoded = decipher.update(encryptedData1, 'binary', 'utf8');
180
- let decoded = decipher.update(encryptedData);
165
+ let decoded = decipher.update(encryptedData1);
181
166
  try {
182
167
  decipher.final('utf-8');
183
168
  } catch (e) {
@@ -215,7 +200,6 @@ async function getChromeCookie({name, domain = '%'}) {
215
200
  if (typeof domain !== 'string') {
216
201
  throw new Error('domain must be a string');
217
202
  }
218
- const chromePasswordPromise = getChromePassword();
219
203
  const encryptedDataItems = await findAllFiles({
220
204
  path: defaultChromeRoot,
221
205
  name: 'Cookies'
@@ -229,25 +213,27 @@ async function getChromeCookie({name, domain = '%'}) {
229
213
  if (process.env.VERBOSE) {
230
214
  console.log("Error getting encrypted cookie", e);
231
215
  }
232
- return null;
216
+ return [];
233
217
  });
234
218
  });
235
- const promise = Promise.all(promises).then(results => {
219
+ return Promise.all(promises).then(results => results.flat()).then(results => {
220
+ if (process.env.VERBOSE) {
221
+ console.log("getEncryptedChromeCookie results", results);
222
+ }
236
223
  return results.filter(result => {
237
224
  return result;
238
225
  });
239
226
  });
240
- if (process.env.VERBOSE) {
241
- console.log('promise', promise);
242
- }
243
- return promise;
244
227
  }).catch(error => {
245
228
  if (process.env.VERBOSE) {
246
229
  console.log('error', error);
247
230
  }
248
231
  return [];
249
232
  });
250
- const password = await chromePasswordPromise;
233
+ const password = await getChromePassword();
234
+ if (process.env.VERBOSE) {
235
+ console.log('encryptedDataItems', encryptedDataItems);
236
+ }
251
237
  const decrypted = encryptedDataItems.filter(encryptedData => {
252
238
  return encryptedData != null && encryptedData.length > 0;
253
239
  }).map(async encryptedData => {
@@ -271,8 +257,12 @@ async function getChromeCookie({name, domain = '%'}) {
271
257
  }
272
258
  return null;
273
259
  });
274
- return await Promise.all(decrypted).then(results => {
275
- return results.find(result => typeof result === 'string' && result.length > 0);
260
+ const results = await Promise.all(decrypted);
261
+ if (process.env.VERBOSE) {
262
+ console.log('results', results);
263
+ }
264
+ return results.map(toStringOrNull).find(result => {
265
+ return typeof result === 'string' && result.length > 0;
276
266
  });
277
267
  }
278
268
 
@@ -349,5 +339,6 @@ module.exports = {
349
339
  getDecryptedCookie: getChromeCookie,
350
340
  getChromeCookie,
351
341
  getFirefoxCookie,
352
- getCookie
342
+ getCookie,
343
+ decrypt
353
344
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mherod/get-cookie",
3
- "version": "1.1.6",
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
6
  "bin": "cli.js",
@@ -8,7 +8,7 @@
8
8
  "access": "public"
9
9
  },
10
10
  "scripts": {
11
- "test": "echo \"Error: no test specified\" && exit 1",
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 CHANGED
@@ -1,6 +1,7 @@
1
1
  // noinspection JSUnusedGlobalSymbols
2
2
 
3
3
  const {exec} = require('child_process');
4
+ const fs = require("fs");
4
5
 
5
6
  async function execSimple(command) {
6
7
  if (typeof command !== 'string') {
@@ -69,8 +70,91 @@ function printStringValue(r) {
69
70
  }
70
71
  }
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
+
72
154
  module.exports = {
73
155
  execSimple: execSimple,
74
156
  execAsBuffer: execAsBuffer,
75
- printStringValue: printStringValue
157
+ printStringValue: printStringValue,
158
+ toStringOrNull: toStringOrNull,
159
+ doSqliteQuery1
76
160
  };