@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.
- package/cli.js +7 -1
- package/index.js +38 -47
- package/package.json +5 -2
- 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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
216
|
+
return [];
|
|
233
217
|
});
|
|
234
218
|
});
|
|
235
|
-
|
|
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
|
|
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
|
-
|
|
275
|
-
|
|
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.
|
|
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": "
|
|
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
|
};
|