@mherod/get-cookie 1.0.4 → 1.1.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/index.js +141 -99
- package/package.json +3 -4
package/index.js
CHANGED
|
@@ -29,6 +29,10 @@ async function getChromePassword() {
|
|
|
29
29
|
});
|
|
30
30
|
}
|
|
31
31
|
|
|
32
|
+
async function getCookie() {
|
|
33
|
+
throw new Error('Not implemented');
|
|
34
|
+
}
|
|
35
|
+
|
|
32
36
|
/**
|
|
33
37
|
*
|
|
34
38
|
* @param name
|
|
@@ -42,51 +46,28 @@ async function getFirefoxCookie({name, domain}) {
|
|
|
42
46
|
if (domain && typeof domain !== 'string') {
|
|
43
47
|
throw new Error('domain must be a string');
|
|
44
48
|
}
|
|
45
|
-
const file = await findFile(`${process.env.HOME}/Library/Application Support/Firefox/Profiles
|
|
49
|
+
const file = await findFile(`${process.env.HOME}/Library/Application Support/Firefox/Profiles`, "cookies.sqlite")
|
|
46
50
|
if (!fs.existsSync(file)) {
|
|
47
51
|
throw new Error(`File ${file} does not exist`);
|
|
48
52
|
}
|
|
49
53
|
if (process.env.VERBOSE) {
|
|
50
54
|
console.log(`Trying Firefox cookie ${name} for domain ${domain}`);
|
|
51
55
|
}
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
sql += `name = '${name}'`;
|
|
59
|
-
if (typeof domain === 'string') {
|
|
60
|
-
sql += ` AND `;
|
|
61
|
-
}
|
|
62
|
-
}
|
|
56
|
+
let sql;
|
|
57
|
+
sql = "SELECT value FROM moz_cookies";
|
|
58
|
+
if (typeof name === 'string' || typeof domain === 'string') {
|
|
59
|
+
sql += ` WHERE `;
|
|
60
|
+
if (typeof name === 'string') {
|
|
61
|
+
sql += `name = '${name}'`;
|
|
63
62
|
if (typeof domain === 'string') {
|
|
64
|
-
sql += `
|
|
63
|
+
sql += ` AND `;
|
|
65
64
|
}
|
|
66
65
|
}
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
console.log(command);
|
|
66
|
+
if (typeof domain === 'string') {
|
|
67
|
+
sql += `host LIKE '${domain}';`;
|
|
70
68
|
}
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
reject(error);
|
|
74
|
-
return;
|
|
75
|
-
}
|
|
76
|
-
if (stderr) {
|
|
77
|
-
reject(error);
|
|
78
|
-
return;
|
|
79
|
-
}
|
|
80
|
-
let stdoutAsBuffer = stdout;
|
|
81
|
-
if (typeof stdoutAsBuffer === 'string' && stdoutAsBuffer.length > 0) {
|
|
82
|
-
// noinspection JSCheckFunctionSignatures
|
|
83
|
-
stdoutAsBuffer = Buffer.from(stdoutAsBuffer, 'binary').slice(0, -1);
|
|
84
|
-
}
|
|
85
|
-
if (stdoutAsBuffer && stdoutAsBuffer.length > 0) {
|
|
86
|
-
resolve(stdoutAsBuffer);
|
|
87
|
-
}
|
|
88
|
-
});
|
|
89
|
-
});
|
|
69
|
+
}
|
|
70
|
+
return await doSqliteQuery1(file, sql);
|
|
90
71
|
}
|
|
91
72
|
|
|
92
73
|
async function getEncryptedChromeCookie(name, domain) {
|
|
@@ -96,34 +77,62 @@ async function getEncryptedChromeCookie(name, domain) {
|
|
|
96
77
|
if (domain && typeof domain !== 'string') {
|
|
97
78
|
throw new Error('domain must be a string');
|
|
98
79
|
}
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
sql
|
|
110
|
-
if (typeof name === 'string'
|
|
111
|
-
sql += `
|
|
112
|
-
if (typeof name === 'string') {
|
|
113
|
-
sql += `name = '${name}'`;
|
|
114
|
-
if (typeof domain === 'string') {
|
|
115
|
-
sql += ` AND `;
|
|
116
|
-
}
|
|
117
|
-
}
|
|
80
|
+
const file = `${process.env.HOME}/Library/Application Support/Google/Chrome/Default/Cookies`;
|
|
81
|
+
if (!fs.existsSync(file)) {
|
|
82
|
+
throw new Error(`File ${file} does not exist`);
|
|
83
|
+
}
|
|
84
|
+
if (process.env.VERBOSE) {
|
|
85
|
+
console.log(`Trying Chrome cookie ${name} for domain ${domain}`);
|
|
86
|
+
}
|
|
87
|
+
let sql;
|
|
88
|
+
sql = `SELECT encrypted_value FROM cookies`;
|
|
89
|
+
if (typeof name === 'string' || typeof domain === 'string') {
|
|
90
|
+
sql += ` WHERE `;
|
|
91
|
+
if (typeof name === 'string') {
|
|
92
|
+
sql += `name = '${name}'`;
|
|
118
93
|
if (typeof domain === 'string') {
|
|
119
|
-
sql += `
|
|
94
|
+
sql += ` AND `;
|
|
120
95
|
}
|
|
121
96
|
}
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
console.log(command);
|
|
97
|
+
if (typeof domain === 'string') {
|
|
98
|
+
sql += `host_key LIKE '${domain}';`;
|
|
125
99
|
}
|
|
126
|
-
|
|
100
|
+
}
|
|
101
|
+
return await doSqliteQuery1(file, sql);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
async function doSqliteQuery1(file, sql) {
|
|
105
|
+
const sqlite3 = require('sqlite3');
|
|
106
|
+
const db = new sqlite3.Database(file);
|
|
107
|
+
return new Promise((resolve, reject) => {
|
|
108
|
+
db.all(sql, (err, rows) => {
|
|
109
|
+
if (err) {
|
|
110
|
+
reject(err);
|
|
111
|
+
return;
|
|
112
|
+
}
|
|
113
|
+
const rows1 = rows;
|
|
114
|
+
if (rows1.length === 0) {
|
|
115
|
+
resolve(null);
|
|
116
|
+
return;
|
|
117
|
+
}
|
|
118
|
+
if (Array.isArray(rows1)) {
|
|
119
|
+
// noinspection JSCheckFunctionSignatures
|
|
120
|
+
const [value] = rows1.flatMap(row => Object.values(row));
|
|
121
|
+
resolve(value);
|
|
122
|
+
return;
|
|
123
|
+
}
|
|
124
|
+
resolve(rows1);
|
|
125
|
+
});
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
async function doSqliteQuery(file, sql) {
|
|
130
|
+
const command = `sqlite3 "${file}" "${sql}"`;
|
|
131
|
+
if (process.env.VERBOSE) {
|
|
132
|
+
console.log(command);
|
|
133
|
+
}
|
|
134
|
+
return await new Promise((resolve, reject) => {
|
|
135
|
+
exec(command, {encoding: 'binary', maxBuffer: 5 * 1024}, (error, stdout, stderr) => {
|
|
127
136
|
if (error) {
|
|
128
137
|
reject(error);
|
|
129
138
|
return;
|
|
@@ -162,45 +171,58 @@ async function decrypt(password, encryptedData) {
|
|
|
162
171
|
}
|
|
163
172
|
return await new Promise((resolve, reject) => {
|
|
164
173
|
crypto.pbkdf2(password, 'saltysalt', 1003, 16, 'sha1', (error, buffer) => {
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
174
|
+
try {
|
|
175
|
+
|
|
176
|
+
if (error) {
|
|
177
|
+
if (process.env.VERBOSE) {
|
|
178
|
+
console.log("Error doing pbkdf2", error);
|
|
179
|
+
}
|
|
180
|
+
reject(error);
|
|
181
|
+
return;
|
|
168
182
|
}
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
183
|
+
if (buffer.length !== 16) {
|
|
184
|
+
if (process.env.VERBOSE) {
|
|
185
|
+
console.log("Error doing pbkdf2, buffer length is not 16", buffer.length);
|
|
186
|
+
}
|
|
187
|
+
reject(new Error('Buffer length is not 16'));
|
|
188
|
+
return;
|
|
175
189
|
}
|
|
176
|
-
reject(new Error('Buffer length is not 16'));
|
|
177
|
-
return;
|
|
178
|
-
}
|
|
179
190
|
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
191
|
+
const iv = new Buffer.from(new Array(17).join(' '), 'binary');
|
|
192
|
+
const decipher = crypto.createDecipheriv('aes-128-cbc', buffer, iv);
|
|
193
|
+
decipher.setAutoPadding(false);
|
|
194
|
+
encryptedData = encryptedData.slice(3);
|
|
184
195
|
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
196
|
+
if (encryptedData.length % 16 !== 0) {
|
|
197
|
+
if (process.env.VERBOSE) {
|
|
198
|
+
console.log("Error doing pbkdf2, encryptedData length is not a multiple of 16", encryptedData.length);
|
|
199
|
+
}
|
|
200
|
+
reject(new Error('encryptedData length is not a multiple of 16'));
|
|
201
|
+
return;
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
let decoded = decipher.update(encryptedData, 'binary', 'utf8');
|
|
205
|
+
// let decoded = decipher.update(encryptedData);
|
|
206
|
+
try {
|
|
207
|
+
decipher.final('utf-8');
|
|
208
|
+
} catch (e) {
|
|
209
|
+
if (process.env.VERBOSE) {
|
|
210
|
+
console.log("Error doing decipher.final()", e);
|
|
211
|
+
}
|
|
212
|
+
reject(e);
|
|
213
|
+
return;
|
|
192
214
|
}
|
|
193
|
-
reject(e);
|
|
194
|
-
return;
|
|
195
|
-
}
|
|
196
215
|
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
216
|
+
let padding = decoded[decoded.length - 1];
|
|
217
|
+
if (padding) {
|
|
218
|
+
decoded = decoded.slice(0, 0 - padding);
|
|
219
|
+
}
|
|
220
|
+
// noinspection JSCheckFunctionSignatures
|
|
221
|
+
decoded = decoded.toString('utf8');
|
|
222
|
+
resolve(decoded);
|
|
223
|
+
} catch (e) {
|
|
224
|
+
reject(e);
|
|
200
225
|
}
|
|
201
|
-
// noinspection JSCheckFunctionSignatures
|
|
202
|
-
decoded = decoded.toString('utf8');
|
|
203
|
-
resolve(decoded)
|
|
204
226
|
});
|
|
205
227
|
});
|
|
206
228
|
}
|
|
@@ -260,18 +282,22 @@ function printStringValue(r) {
|
|
|
260
282
|
if (process.env.VERBOSE) {
|
|
261
283
|
console.log("Printing value", r);
|
|
262
284
|
}
|
|
263
|
-
if (
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
285
|
+
if (r) {
|
|
286
|
+
if (typeof r === 'string') {
|
|
287
|
+
console.log(r);
|
|
288
|
+
} else if (r.toString) {
|
|
289
|
+
// noinspection JSCheckFunctionSignatures
|
|
290
|
+
console.log(r.toString('utf8'));
|
|
291
|
+
}
|
|
268
292
|
}
|
|
269
293
|
}
|
|
270
294
|
|
|
271
295
|
// noinspection JSUnusedGlobalSymbols
|
|
272
296
|
module.exports = {
|
|
273
297
|
getDecryptedCookie: getChromeCookie,
|
|
274
|
-
getChromeCookie
|
|
298
|
+
getChromeCookie,
|
|
299
|
+
getFirefoxCookie,
|
|
300
|
+
getCookie
|
|
275
301
|
};
|
|
276
302
|
|
|
277
303
|
if (process.argv) {
|
|
@@ -292,12 +318,22 @@ if (process.argv) {
|
|
|
292
318
|
process.env.IGNORE_EXPIRED = "true";
|
|
293
319
|
}
|
|
294
320
|
|
|
321
|
+
if (process.env.VERBOSE) {
|
|
322
|
+
console.log("Verbose mode", process.argv);
|
|
323
|
+
}
|
|
324
|
+
|
|
295
325
|
if (process.env.CHROME_ONLY) {
|
|
296
326
|
if (process.env.VERBOSE) {
|
|
297
327
|
console.log('chrome only');
|
|
298
328
|
}
|
|
299
329
|
getChromeCookie({name, domain})
|
|
300
|
-
.then(
|
|
330
|
+
.then(cookie => {
|
|
331
|
+
if (cookie && cookie.length > 0) {
|
|
332
|
+
printStringValue(cookie);
|
|
333
|
+
} else {
|
|
334
|
+
console.log('No cookie found');
|
|
335
|
+
}
|
|
336
|
+
})
|
|
301
337
|
.catch(err => {
|
|
302
338
|
if (process.env.VERBOSE) {
|
|
303
339
|
console.error(err);
|
|
@@ -308,7 +344,13 @@ if (process.argv) {
|
|
|
308
344
|
console.log('firefox only');
|
|
309
345
|
}
|
|
310
346
|
getFirefoxCookie({name, domain})
|
|
311
|
-
.then(
|
|
347
|
+
.then(cookie => {
|
|
348
|
+
if (cookie && cookie.length > 0) {
|
|
349
|
+
printStringValue(cookie);
|
|
350
|
+
} else {
|
|
351
|
+
console.log('No cookie found');
|
|
352
|
+
}
|
|
353
|
+
})
|
|
312
354
|
.catch(err => {
|
|
313
355
|
if (process.env.VERBOSE) {
|
|
314
356
|
console.error("Error getting Firefox cookie", err);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mherod/get-cookie",
|
|
3
|
-
"version": "1.0
|
|
3
|
+
"version": "1.1.0",
|
|
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,13 +9,12 @@
|
|
|
9
9
|
},
|
|
10
10
|
"scripts": {
|
|
11
11
|
"test": "echo \"Error: no test specified\" && exit 1",
|
|
12
|
-
"
|
|
13
|
-
"installForMac": "pkg . --target node17-macos-x64 --out-path /usr/local/bin/ --debug",
|
|
14
|
-
"installForHost": "pkg . --target host --out-path /usr/local/bin/ --debug"
|
|
12
|
+
"install": "npm install --force --global ."
|
|
15
13
|
},
|
|
16
14
|
"keywords": [],
|
|
17
15
|
"author": "Matthew Herod",
|
|
18
16
|
"license": "ISC",
|
|
19
17
|
"dependencies": {
|
|
18
|
+
"sqlite3": "^5.0.8"
|
|
20
19
|
}
|
|
21
20
|
}
|