@mherod/get-cookie 1.1.0 → 1.1.3
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/index.js +84 -16
- package/package.json +2 -2
package/index.js
CHANGED
|
@@ -70,19 +70,24 @@ async function getFirefoxCookie({name, domain}) {
|
|
|
70
70
|
return await doSqliteQuery1(file, sql);
|
|
71
71
|
}
|
|
72
72
|
|
|
73
|
-
|
|
73
|
+
const defaultChromeRoot = `${process.env.HOME}/Library/Application Support/Google/Chrome`;
|
|
74
|
+
const defaultChromeCookies = `${defaultChromeRoot}/Default/Cookies`;
|
|
75
|
+
|
|
76
|
+
async function getEncryptedChromeCookie(name, domain, file = defaultChromeCookies) {
|
|
74
77
|
if (name && typeof name !== 'string') {
|
|
75
78
|
throw new Error('name must be a string');
|
|
76
79
|
}
|
|
77
80
|
if (domain && typeof domain !== 'string') {
|
|
78
81
|
throw new Error('domain must be a string');
|
|
79
82
|
}
|
|
80
|
-
|
|
83
|
+
if (file && typeof file !== 'string') {
|
|
84
|
+
throw new Error('file must be a string');
|
|
85
|
+
}
|
|
81
86
|
if (!fs.existsSync(file)) {
|
|
82
87
|
throw new Error(`File ${file} does not exist`);
|
|
83
88
|
}
|
|
84
89
|
if (process.env.VERBOSE) {
|
|
85
|
-
console.log(`Trying Chrome cookie ${name} for domain ${domain}`);
|
|
90
|
+
console.log(`Trying Chrome (at ${file}) cookie ${name} for domain ${domain}`);
|
|
86
91
|
}
|
|
87
92
|
let sql;
|
|
88
93
|
sql = `SELECT encrypted_value FROM cookies`;
|
|
@@ -112,13 +117,16 @@ async function doSqliteQuery1(file, sql) {
|
|
|
112
117
|
}
|
|
113
118
|
const rows1 = rows;
|
|
114
119
|
if (rows1.length === 0) {
|
|
120
|
+
if (process.env.VERBOSE) {
|
|
121
|
+
console.log(`No rows found`);
|
|
122
|
+
}
|
|
115
123
|
resolve(null);
|
|
116
124
|
return;
|
|
117
125
|
}
|
|
118
126
|
if (Array.isArray(rows1)) {
|
|
119
127
|
// noinspection JSCheckFunctionSignatures
|
|
120
128
|
const [value] = rows1.flatMap(row => Object.values(row));
|
|
121
|
-
resolve(value);
|
|
129
|
+
resolve(Buffer.from(value));
|
|
122
130
|
return;
|
|
123
131
|
}
|
|
124
132
|
resolve(rows1);
|
|
@@ -161,10 +169,11 @@ async function doSqliteQuery(file, sql) {
|
|
|
161
169
|
*/
|
|
162
170
|
async function decrypt(password, encryptedData) {
|
|
163
171
|
if (typeof password !== 'string') {
|
|
164
|
-
throw new Error('password must be a string');
|
|
172
|
+
throw new Error('password must be a string: ' + password);
|
|
165
173
|
}
|
|
166
|
-
|
|
167
|
-
|
|
174
|
+
const encryptedData1 = encryptedData;
|
|
175
|
+
if (encryptedData1 == null || typeof encryptedData1 !== 'object') {
|
|
176
|
+
throw new Error('encryptedData must be a object: ' + encryptedData1);
|
|
168
177
|
}
|
|
169
178
|
if (process.env.VERBOSE) {
|
|
170
179
|
console.log(`Trying to decrypt with password ${password}`);
|
|
@@ -172,7 +181,6 @@ async function decrypt(password, encryptedData) {
|
|
|
172
181
|
return await new Promise((resolve, reject) => {
|
|
173
182
|
crypto.pbkdf2(password, 'saltysalt', 1003, 16, 'sha1', (error, buffer) => {
|
|
174
183
|
try {
|
|
175
|
-
|
|
176
184
|
if (error) {
|
|
177
185
|
if (process.env.VERBOSE) {
|
|
178
186
|
console.log("Error doing pbkdf2", error);
|
|
@@ -180,6 +188,7 @@ async function decrypt(password, encryptedData) {
|
|
|
180
188
|
reject(error);
|
|
181
189
|
return;
|
|
182
190
|
}
|
|
191
|
+
|
|
183
192
|
if (buffer.length !== 16) {
|
|
184
193
|
if (process.env.VERBOSE) {
|
|
185
194
|
console.log("Error doing pbkdf2, buffer length is not 16", buffer.length);
|
|
@@ -191,17 +200,20 @@ async function decrypt(password, encryptedData) {
|
|
|
191
200
|
const iv = new Buffer.from(new Array(17).join(' '), 'binary');
|
|
192
201
|
const decipher = crypto.createDecipheriv('aes-128-cbc', buffer, iv);
|
|
193
202
|
decipher.setAutoPadding(false);
|
|
194
|
-
encryptedData = encryptedData.slice(3);
|
|
195
203
|
|
|
196
|
-
if (
|
|
204
|
+
if (encryptedData1 && encryptedData1.slice) {
|
|
205
|
+
encryptedData = encryptedData1.slice(3);
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
if (encryptedData1.length % 16 !== 0) {
|
|
197
209
|
if (process.env.VERBOSE) {
|
|
198
|
-
console.log("Error doing pbkdf2, encryptedData length is not a multiple of 16",
|
|
210
|
+
console.log("Error doing pbkdf2, encryptedData length is not a multiple of 16", encryptedData1.length);
|
|
199
211
|
}
|
|
200
212
|
reject(new Error('encryptedData length is not a multiple of 16'));
|
|
201
213
|
return;
|
|
202
214
|
}
|
|
203
215
|
|
|
204
|
-
let decoded = decipher.update(
|
|
216
|
+
let decoded = decipher.update(encryptedData1, 'binary', 'utf8');
|
|
205
217
|
// let decoded = decipher.update(encryptedData);
|
|
206
218
|
try {
|
|
207
219
|
decipher.final('utf-8');
|
|
@@ -240,8 +252,11 @@ async function getChromeCookie({name, domain}) {
|
|
|
240
252
|
if (domain && typeof domain !== 'string') {
|
|
241
253
|
throw new Error('domain must be a string');
|
|
242
254
|
}
|
|
243
|
-
const
|
|
244
|
-
const encryptedData = await
|
|
255
|
+
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)));
|
|
258
|
+
});
|
|
259
|
+
const password = await chromePasswordPromise;
|
|
245
260
|
if (process.env.VERBOSE) {
|
|
246
261
|
console.log("Received encrypted", encryptedData);
|
|
247
262
|
}
|
|
@@ -249,7 +264,9 @@ async function getChromeCookie({name, domain}) {
|
|
|
249
264
|
try {
|
|
250
265
|
s = await decrypt(password, encryptedData);
|
|
251
266
|
} catch (e) {
|
|
252
|
-
|
|
267
|
+
if (process.env.VERBOSE) {
|
|
268
|
+
console.error("Error decrypting", e);
|
|
269
|
+
}
|
|
253
270
|
throw new Error('Failed to decrypt');
|
|
254
271
|
}
|
|
255
272
|
if (process.env.VERBOSE) {
|
|
@@ -258,6 +275,57 @@ async function getChromeCookie({name, domain}) {
|
|
|
258
275
|
return s;
|
|
259
276
|
}
|
|
260
277
|
|
|
278
|
+
/**
|
|
279
|
+
*
|
|
280
|
+
* @param path
|
|
281
|
+
* @param name
|
|
282
|
+
* @param rootSegments
|
|
283
|
+
* @param maxDepth
|
|
284
|
+
* @returns {Promise<[string]>}
|
|
285
|
+
*/
|
|
286
|
+
async function findAllFiles({path, name, rootSegments = path.split('/').length, maxDepth = 2}) {
|
|
287
|
+
if (typeof path !== 'string') {
|
|
288
|
+
throw new Error('path must be a string');
|
|
289
|
+
}
|
|
290
|
+
if (typeof name !== 'string') {
|
|
291
|
+
throw new Error('name must be a string');
|
|
292
|
+
}
|
|
293
|
+
if (process.env.VERBOSE) {
|
|
294
|
+
console.log(`Searching for ${name} in ${path}`);
|
|
295
|
+
}
|
|
296
|
+
const files = [];
|
|
297
|
+
for (const file of fs.readdirSync(path)) {
|
|
298
|
+
const filePath = path + '/' + file;
|
|
299
|
+
const stat = fs.statSync(filePath);
|
|
300
|
+
if (stat.isDirectory()) {
|
|
301
|
+
if (filePath.split('/').length < rootSegments + maxDepth) {
|
|
302
|
+
try {
|
|
303
|
+
const subFiles = await findAllFiles({
|
|
304
|
+
path: filePath,
|
|
305
|
+
name: name,
|
|
306
|
+
rootSegments: rootSegments,
|
|
307
|
+
maxDepth: 2
|
|
308
|
+
});
|
|
309
|
+
files.push(...subFiles);
|
|
310
|
+
} catch (e) {
|
|
311
|
+
if (process.env.VERBOSE) {
|
|
312
|
+
console.error(e);
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
} else if (file === name) {
|
|
317
|
+
files.push(filePath);
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
if (process.env.VERBOSE) {
|
|
321
|
+
if (files.length > 0) {
|
|
322
|
+
console.log(`Found ${(files.length)} ${name} files`);
|
|
323
|
+
console.log(files);
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
return files;
|
|
327
|
+
}
|
|
328
|
+
|
|
261
329
|
/**
|
|
262
330
|
*
|
|
263
331
|
* @param path
|
|
@@ -303,7 +371,7 @@ module.exports = {
|
|
|
303
371
|
if (process.argv) {
|
|
304
372
|
if (process.argv.length > 2) {
|
|
305
373
|
const name = process.argv[2];
|
|
306
|
-
const domain = process.argv[3];
|
|
374
|
+
const domain = process.argv[3] ?? '%';
|
|
307
375
|
|
|
308
376
|
if (process.argv.includes('--verbose')) {
|
|
309
377
|
process.env.VERBOSE = "true";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mherod/get-cookie",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.3",
|
|
4
4
|
"description": "Node.js module for querying a local user's Chrome cookie",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"bin": "index.js",
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
},
|
|
10
10
|
"scripts": {
|
|
11
11
|
"test": "echo \"Error: no test specified\" && exit 1",
|
|
12
|
-
"
|
|
12
|
+
"installGlobal": "rm -rf /usr/local/bin/get-cookie ; npm install --force --global ."
|
|
13
13
|
},
|
|
14
14
|
"keywords": [],
|
|
15
15
|
"author": "Matthew Herod",
|