@mherod/get-cookie 2.0.0-beta.1 → 2.0.0-beta.4
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/.idea/codeStyles/Project.xml +59 -0
- package/.idea/codeStyles/codeStyleConfig.xml +5 -0
- package/.idea/get-cookie.iml +1 -0
- package/.prettierrc.json +1 -0
- package/dist/cli.js +1 -1
- package/dist/cli.js.map +1 -1
- package/dist/index.js +3 -0
- package/dist/index.js.map +1 -0
- package/dist/main.js +196 -220
- package/dist/main.js.map +1 -1
- package/dist/module.js +466 -0
- package/dist/module.js.map +1 -0
- package/dist/types.d.ts +25 -0
- package/dist/types.d.ts.map +1 -0
- package/package.json +27 -12
- package/src/CookieRow.ts +21 -0
- package/src/argv.ts +1 -0
- package/src/browsers/{AbstractCookieQueryStrategy.js → AbstractCookieQueryStrategy.ts} +3 -1
- package/src/browsers/ChromeCookieQueryStrategy.ts +256 -0
- package/src/browsers/{CompositeCookieQueryStrategy.js → CompositeCookieQueryStrategy.ts} +5 -2
- package/src/browsers/{FirefoxCookieQueryStrategy.js → FirefoxCookieQueryStrategy.ts} +28 -13
- package/src/browsers/{SafariCookieQueryStrategy.js → SafariCookieQueryStrategy.ts} +0 -0
- package/src/cli.ts +85 -0
- package/src/doSqliteQuery1.ts +47 -0
- package/src/{findAllFiles.js → findAllFiles.ts} +15 -20
- package/src/{global.js → global.ts} +2 -2
- package/src/{index.js → index.ts} +3 -8
- package/src/{isValidJwt.js → isValidJwt.ts} +1 -4
- package/src/queryCookies.ts +29 -0
- package/src/utils.ts +118 -0
- package/tsconfig.json +23 -0
- package/src/browsers/ChromeCookieQueryStrategy.js +0 -263
- package/src/cli.js +0 -70
- package/src/queryCookies.js +0 -28
- package/src/utils.js +0 -181
package/src/cli.ts
ADDED
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import { env } from "./global";
|
|
4
|
+
import { queryCookies } from "./queryCookies";
|
|
5
|
+
import { argv } from "./argv";
|
|
6
|
+
import { groupBy, uniqBy } from "lodash";
|
|
7
|
+
import { blue, green } from "colorette";
|
|
8
|
+
import { ExportedCookie } from "./CookieRow";
|
|
9
|
+
|
|
10
|
+
function combinedString(results: ExportedCookie[]) {
|
|
11
|
+
return blue(
|
|
12
|
+
uniqBy(results, (r) => r.name)
|
|
13
|
+
.map((r) => r.name + "=" + r.value)
|
|
14
|
+
.join("; ")
|
|
15
|
+
);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
async function cliQueryCookies(name: string, domain: string) {
|
|
19
|
+
try {
|
|
20
|
+
const results = await queryCookies({ name, domain });
|
|
21
|
+
if (results.length > 0) {
|
|
22
|
+
if (argv.includes("--combined-string")) {
|
|
23
|
+
console.log(combinedString(results));
|
|
24
|
+
} else if (argv.includes("--dump")) {
|
|
25
|
+
console.log(results);
|
|
26
|
+
} else if (argv.includes("--dump-grouped")) {
|
|
27
|
+
const groupedByFile = groupBy(results, (r) => r.meta?.file);
|
|
28
|
+
console.log(green(JSON.stringify(groupedByFile, null, 2)));
|
|
29
|
+
} else if (argv.includes("--combined-string-grouped")) {
|
|
30
|
+
const groupedByFile = groupBy(results, (r) => r.meta?.file);
|
|
31
|
+
for (const file of Object.keys(groupedByFile)) {
|
|
32
|
+
let results = groupedByFile[file];
|
|
33
|
+
console.log(green(file) + ": ", combinedString(results));
|
|
34
|
+
}
|
|
35
|
+
} else {
|
|
36
|
+
for (const result of results) {
|
|
37
|
+
console.log(result.value);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
} else {
|
|
41
|
+
console.error("No results");
|
|
42
|
+
}
|
|
43
|
+
} catch (e) {
|
|
44
|
+
console.error(e);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
if (argv && argv.length > 2) {
|
|
49
|
+
const name = argv[2];
|
|
50
|
+
|
|
51
|
+
let domain;
|
|
52
|
+
if (argv[3] != null && argv[3].indexOf(".") > -1) {
|
|
53
|
+
domain = argv[3];
|
|
54
|
+
} else {
|
|
55
|
+
domain = "%";
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
const tru = `${true}`;
|
|
59
|
+
|
|
60
|
+
if (argv.includes("--require-jwt")) {
|
|
61
|
+
env.REQUIRE_JWT = tru;
|
|
62
|
+
}
|
|
63
|
+
if (argv.includes("--verbose")) {
|
|
64
|
+
env.VERBOSE = tru;
|
|
65
|
+
}
|
|
66
|
+
if (argv.includes("--chrome-only")) {
|
|
67
|
+
env.CHROME_ONLY = tru;
|
|
68
|
+
}
|
|
69
|
+
if (argv.includes("--firefox-only")) {
|
|
70
|
+
env.FIREFOX_ONLY = tru;
|
|
71
|
+
}
|
|
72
|
+
if (argv.includes("--ignore-expired")) {
|
|
73
|
+
env.IGNORE_EXPIRED = tru;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
if (argv.includes("--single")) {
|
|
77
|
+
env.SINGLE = tru;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
if (env.VERBOSE) {
|
|
81
|
+
console.log("Verbose mode", argv);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
cliQueryCookies(name, domain).catch(console.error);
|
|
85
|
+
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import * as fs from "fs";
|
|
2
|
+
import * as sqlite3 from "sqlite3";
|
|
3
|
+
import {CookieRow} from "./CookieRow";
|
|
4
|
+
|
|
5
|
+
export async function doSqliteQuery1(file: string, sql: string): Promise<CookieRow[]> {
|
|
6
|
+
if (!fs.existsSync(file)) {
|
|
7
|
+
throw new Error(`doSqliteQuery1: file ${file} does not exist`);
|
|
8
|
+
}
|
|
9
|
+
const db = new sqlite3.Database(file);
|
|
10
|
+
return new Promise((resolve, reject) => {
|
|
11
|
+
db.all(sql, (err: Error, rows: any[]) => {
|
|
12
|
+
if (err) {
|
|
13
|
+
if (process.env.VERBOSE) {
|
|
14
|
+
console.log(`doSqliteQuery1: error ${err}`);
|
|
15
|
+
}
|
|
16
|
+
reject(err);
|
|
17
|
+
return;
|
|
18
|
+
}
|
|
19
|
+
const rows1: any[] = rows;
|
|
20
|
+
if (rows1 == null || rows1.length === 0) {
|
|
21
|
+
if (process.env.VERBOSE) {
|
|
22
|
+
console.log(`doSqliteQuery1: no rows`);
|
|
23
|
+
}
|
|
24
|
+
resolve([]);
|
|
25
|
+
return;
|
|
26
|
+
}
|
|
27
|
+
if (Array.isArray(rows1)) {
|
|
28
|
+
const cookieRows: CookieRow[] = rows1.map((row) => {
|
|
29
|
+
return {
|
|
30
|
+
domain: row["host_key"],
|
|
31
|
+
name: row["name"],
|
|
32
|
+
value: row["encrypted_value"],
|
|
33
|
+
meta: {
|
|
34
|
+
file: file
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
})
|
|
38
|
+
resolve(cookieRows);
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
if (process.env.VERBOSE) {
|
|
42
|
+
console.log(`doSqliteQuery1: rows ${JSON.stringify(rows1)}`);
|
|
43
|
+
}
|
|
44
|
+
resolve([rows1]);
|
|
45
|
+
});
|
|
46
|
+
});
|
|
47
|
+
}
|
|
@@ -1,28 +1,24 @@
|
|
|
1
1
|
import { env } from "./global";
|
|
2
|
-
import fs from "fs";
|
|
2
|
+
import * as fs from "fs";
|
|
3
3
|
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
throw new Error("path must be a string");
|
|
4
|
+
export async function findAllFiles(
|
|
5
|
+
{
|
|
6
|
+
path,
|
|
7
|
+
name,
|
|
8
|
+
maxDepth = 2
|
|
9
|
+
//
|
|
10
|
+
}: {
|
|
11
|
+
path: string;
|
|
12
|
+
name: string;
|
|
13
|
+
maxDepth?: number;
|
|
15
14
|
}
|
|
16
|
-
|
|
17
|
-
throw new Error("name must be a string");
|
|
18
|
-
}
|
|
19
|
-
|
|
15
|
+
): Promise<string[]> {
|
|
20
16
|
const rootSegments = path.split("/").length;
|
|
21
17
|
|
|
22
18
|
if (env.VERBOSE) {
|
|
23
19
|
console.log(`Searching for ${name} in ${path}`);
|
|
24
20
|
}
|
|
25
|
-
const files = [];
|
|
21
|
+
const files: string[] = [];
|
|
26
22
|
let readdirSync;
|
|
27
23
|
try {
|
|
28
24
|
readdirSync = fs.readdirSync(path);
|
|
@@ -30,7 +26,7 @@ export async function findAllFiles({ path, name, maxDepth = 2 }) {
|
|
|
30
26
|
if (env.VERBOSE) {
|
|
31
27
|
console.log(`Error reading ${path}`, e);
|
|
32
28
|
}
|
|
33
|
-
return
|
|
29
|
+
return [];
|
|
34
30
|
}
|
|
35
31
|
for (const file of readdirSync) {
|
|
36
32
|
const filePath = path + "/" + file;
|
|
@@ -49,8 +45,7 @@ export async function findAllFiles({ path, name, maxDepth = 2 }) {
|
|
|
49
45
|
const subFiles = await findAllFiles({
|
|
50
46
|
path: filePath,
|
|
51
47
|
name: name,
|
|
52
|
-
|
|
53
|
-
maxDepth: 2,
|
|
48
|
+
maxDepth: 2
|
|
54
49
|
});
|
|
55
50
|
files.push(...subFiles);
|
|
56
51
|
} catch (e) {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
const { merge } = require("lodash");
|
|
2
|
-
export const env = {};
|
|
2
|
+
export const env: any = {};
|
|
3
3
|
merge(env, process.env);
|
|
4
|
-
export const HOME = env["HOME"];
|
|
4
|
+
export const HOME: string = env["HOME"];
|
|
5
5
|
if (!HOME) {
|
|
6
6
|
throw new Error("HOME environment variable is not set");
|
|
7
7
|
}
|
|
@@ -6,12 +6,7 @@ import FirefoxCookieQueryStrategy from "./browsers/FirefoxCookieQueryStrategy";
|
|
|
6
6
|
import ChromeCookieQueryStrategy from "./browsers/ChromeCookieQueryStrategy";
|
|
7
7
|
import CompositeCookieQueryStrategy from "./browsers/CompositeCookieQueryStrategy";
|
|
8
8
|
|
|
9
|
-
|
|
10
|
-
*
|
|
11
|
-
* @param params
|
|
12
|
-
* @returns {Promise<string>}
|
|
13
|
-
*/
|
|
14
|
-
export async function getCookie(params) {
|
|
9
|
+
export async function getCookie(params: { name: string; domain: string; }) {
|
|
15
10
|
const cookies = await queryCookies(
|
|
16
11
|
params,
|
|
17
12
|
new CompositeCookieQueryStrategy()
|
|
@@ -29,7 +24,7 @@ export async function getCookie(params) {
|
|
|
29
24
|
* @param params
|
|
30
25
|
* @returns {Promise<*>}
|
|
31
26
|
*/
|
|
32
|
-
export async function getFirefoxCookie(params) {
|
|
27
|
+
export async function getFirefoxCookie(params: { name: string; domain: string; }) {
|
|
33
28
|
const cookies = await queryCookies(
|
|
34
29
|
params,
|
|
35
30
|
new FirefoxCookieQueryStrategy()
|
|
@@ -47,7 +42,7 @@ export async function getFirefoxCookie(params) {
|
|
|
47
42
|
* @param params
|
|
48
43
|
* @returns {Promise<*>}
|
|
49
44
|
*/
|
|
50
|
-
export async function getChromeCookie(params) {
|
|
45
|
+
export async function getChromeCookie(params: { name: string; domain: string; }) {
|
|
51
46
|
const cookies = await queryCookies(
|
|
52
47
|
params,
|
|
53
48
|
new ChromeCookieQueryStrategy()
|
|
@@ -1,10 +1,7 @@
|
|
|
1
1
|
import jsonwebtoken from "jsonwebtoken";
|
|
2
2
|
import { env } from "./global";
|
|
3
3
|
|
|
4
|
-
export default function isValidJwt(token) {
|
|
5
|
-
if (typeof token !== "string") {
|
|
6
|
-
return false;
|
|
7
|
-
}
|
|
4
|
+
export default function isValidJwt(token: any) {
|
|
8
5
|
try {
|
|
9
6
|
const result = jsonwebtoken.decode(token, { complete: true });
|
|
10
7
|
if (env.VERBOSE) {
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import CompositeCookieQueryStrategy from "./browsers/CompositeCookieQueryStrategy";
|
|
2
|
+
import { uniqBy } from "lodash";
|
|
3
|
+
import { env } from "./global";
|
|
4
|
+
import isValidJwt from "./isValidJwt";
|
|
5
|
+
import { ExportedCookie } from "./CookieRow";
|
|
6
|
+
import AbstractCookieQueryStrategy from "./browsers/AbstractCookieQueryStrategy";
|
|
7
|
+
|
|
8
|
+
export async function queryCookies(
|
|
9
|
+
{
|
|
10
|
+
name,
|
|
11
|
+
domain
|
|
12
|
+
}: {
|
|
13
|
+
name: string;
|
|
14
|
+
domain: string;
|
|
15
|
+
},
|
|
16
|
+
strategy: AbstractCookieQueryStrategy = new CompositeCookieQueryStrategy()
|
|
17
|
+
) {
|
|
18
|
+
const results: ExportedCookie[] = await strategy.queryCookies(name, domain);
|
|
19
|
+
const results1: ExportedCookie[] = uniqBy(results, JSON.stringify);
|
|
20
|
+
const jwtCookies = [];
|
|
21
|
+
for (const result of results1) {
|
|
22
|
+
const value = result.value;
|
|
23
|
+
if (isValidJwt(value)) {
|
|
24
|
+
jwtCookies.push(result);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
const resultsUniq = env.REQUIRE_JWT ? jwtCookies : results1;
|
|
28
|
+
return env.SINGLE ? [resultsUniq[0]] : resultsUniq;
|
|
29
|
+
}
|
package/src/utils.ts
ADDED
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
// noinspection JSUnusedGlobalSymbols
|
|
2
|
+
|
|
3
|
+
import {exec, ExecException} from "child_process";
|
|
4
|
+
|
|
5
|
+
export async function execSimple(command: string): Promise<string> {
|
|
6
|
+
if (process.env.VERBOSE) {
|
|
7
|
+
console.log(command);
|
|
8
|
+
}
|
|
9
|
+
return new Promise((resolve, reject) => {
|
|
10
|
+
exec(
|
|
11
|
+
command,
|
|
12
|
+
{ encoding: "binary", maxBuffer: 5 * 1024 },
|
|
13
|
+
(error: ExecException | null, stdout: string, stderr: string) => {
|
|
14
|
+
if (error) {
|
|
15
|
+
reject(error);
|
|
16
|
+
return;
|
|
17
|
+
}
|
|
18
|
+
if (stderr) {
|
|
19
|
+
reject(error);
|
|
20
|
+
return;
|
|
21
|
+
}
|
|
22
|
+
if (stdout) {
|
|
23
|
+
resolve(stdout.trim());
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
);
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
// export async function execAsBuffer(command: string) {
|
|
31
|
+
// if (process.env.VERBOSE) {
|
|
32
|
+
// console.log(command);
|
|
33
|
+
// }
|
|
34
|
+
// return await new Promise((resolve, reject) => {
|
|
35
|
+
// exec(
|
|
36
|
+
// command,
|
|
37
|
+
// { encoding: "binary", maxBuffer: 5 * 1024 },
|
|
38
|
+
// (error: ExecException | null, stdout: string, stderr: string) => {
|
|
39
|
+
// if (error) {
|
|
40
|
+
// reject(error);
|
|
41
|
+
// return;
|
|
42
|
+
// }
|
|
43
|
+
// if (stderr) {
|
|
44
|
+
// reject(error);
|
|
45
|
+
// return;
|
|
46
|
+
// }
|
|
47
|
+
// let stdoutAsBuffer: string = stdout;
|
|
48
|
+
// if (typeof stdoutAsBuffer === "string" && stdoutAsBuffer.length > 0) {
|
|
49
|
+
// // noinspection JSCheckFunctionSignatures
|
|
50
|
+
// stdoutAsBuffer = Buffer.from(stdoutAsBuffer, "binary").slice(0, -1);
|
|
51
|
+
// }
|
|
52
|
+
// if (stdoutAsBuffer && stdoutAsBuffer.length > 0) {
|
|
53
|
+
// resolve(stdoutAsBuffer);
|
|
54
|
+
// }
|
|
55
|
+
// }
|
|
56
|
+
// );
|
|
57
|
+
// });
|
|
58
|
+
// }
|
|
59
|
+
|
|
60
|
+
// @ts-ignore
|
|
61
|
+
export function toStringValue(r: any): string {
|
|
62
|
+
if (process.env.VERBOSE) {
|
|
63
|
+
console.log("Printing value", r);
|
|
64
|
+
}
|
|
65
|
+
if (r) {
|
|
66
|
+
if (typeof r === "string") {
|
|
67
|
+
return r;
|
|
68
|
+
} else if (r.toString) {
|
|
69
|
+
// noinspection JSCheckFunctionSignatures
|
|
70
|
+
return r.toString("utf8");
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
export function printStringValue(r: any) {
|
|
76
|
+
if (process.env.VERBOSE) {
|
|
77
|
+
console.log("Printing value", r);
|
|
78
|
+
}
|
|
79
|
+
if (r) {
|
|
80
|
+
if (typeof r === "string") {
|
|
81
|
+
console.log(r);
|
|
82
|
+
} else if (r.toString) {
|
|
83
|
+
// noinspection JSCheckFunctionSignatures
|
|
84
|
+
console.log(r.toString("utf8"));
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
*
|
|
91
|
+
* @param result
|
|
92
|
+
* @returns {string|null}
|
|
93
|
+
*/
|
|
94
|
+
export function toStringOrNull(result: any) {
|
|
95
|
+
if (result == null) {
|
|
96
|
+
return null;
|
|
97
|
+
}
|
|
98
|
+
if (process.env.VERBOSE) {
|
|
99
|
+
console.log("result", result);
|
|
100
|
+
}
|
|
101
|
+
if (typeof result === "string" && result.length > 0) {
|
|
102
|
+
return result;
|
|
103
|
+
}
|
|
104
|
+
if (result.slice && result.toString) {
|
|
105
|
+
// noinspection JSCheckFunctionSignatures
|
|
106
|
+
return result.toString("utf8");
|
|
107
|
+
}
|
|
108
|
+
return null;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
export function invalidString(input: any): boolean {
|
|
112
|
+
return typeof input !== "string" || input.length === 0;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
export function validString(input: any): input is string {
|
|
117
|
+
return typeof input == "string" && input.length > 0;
|
|
118
|
+
}
|
package/tsconfig.json
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
{
|
|
2
|
+
"include": [
|
|
3
|
+
"src/**.ts",
|
|
4
|
+
"src/**.tsx",
|
|
5
|
+
"src/**.js",
|
|
6
|
+
"src/**.jsx"
|
|
7
|
+
],
|
|
8
|
+
"compilerOptions": {
|
|
9
|
+
"moduleResolution": "node",
|
|
10
|
+
"target": "es2021",
|
|
11
|
+
"types": [
|
|
12
|
+
"node"
|
|
13
|
+
],
|
|
14
|
+
"lib": [
|
|
15
|
+
"es2015",
|
|
16
|
+
"es2017",
|
|
17
|
+
"es2021",
|
|
18
|
+
"dom"
|
|
19
|
+
],
|
|
20
|
+
"strict": true,
|
|
21
|
+
"allowSyntheticDefaultImports": true,
|
|
22
|
+
}
|
|
23
|
+
}
|
|
@@ -1,263 +0,0 @@
|
|
|
1
|
-
import AbstractCookieQueryStrategy from "./AbstractCookieQueryStrategy";
|
|
2
|
-
import {
|
|
3
|
-
doSqliteQuery1,
|
|
4
|
-
execSimple,
|
|
5
|
-
invalidString,
|
|
6
|
-
toStringOrNull,
|
|
7
|
-
toStringValue,
|
|
8
|
-
} from "../utils";
|
|
9
|
-
import { env, HOME } from "../global";
|
|
10
|
-
import { existsSync } from "fs";
|
|
11
|
-
import { findAllFiles } from "../findAllFiles";
|
|
12
|
-
import crypto from "crypto";
|
|
13
|
-
import * as path from "path";
|
|
14
|
-
|
|
15
|
-
export default class ChromeCookieQueryStrategy extends AbstractCookieQueryStrategy {
|
|
16
|
-
async queryCookies(name, domain) {
|
|
17
|
-
if (process.platform !== "darwin") {
|
|
18
|
-
throw new Error("This only works on macOS");
|
|
19
|
-
}
|
|
20
|
-
if (env.FIREFOX_ONLY) {
|
|
21
|
-
return [];
|
|
22
|
-
}
|
|
23
|
-
const cookies = await getChromeCookies({ name, domain });
|
|
24
|
-
return cookies.map(toStringValue);
|
|
25
|
-
}
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
async function getPromise1(name, domain, file) {
|
|
29
|
-
try {
|
|
30
|
-
return await getEncryptedChromeCookie({
|
|
31
|
-
name: name,
|
|
32
|
-
domain: domain,
|
|
33
|
-
file: file,
|
|
34
|
-
});
|
|
35
|
-
} catch (e) {
|
|
36
|
-
if (env.VERBOSE) {
|
|
37
|
-
console.log("Error getting encrypted cookie", e);
|
|
38
|
-
}
|
|
39
|
-
return [];
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
async function getPromise(name, domain) {
|
|
44
|
-
try {
|
|
45
|
-
const files = await findAllFiles({
|
|
46
|
-
path: chromeLocal,
|
|
47
|
-
name: "Cookies",
|
|
48
|
-
});
|
|
49
|
-
const promises = files.map((file) => getPromise1(name, domain, file));
|
|
50
|
-
const results1 = await Promise.all(promises);
|
|
51
|
-
const results2 = results1.flat();
|
|
52
|
-
if (env.VERBOSE) {
|
|
53
|
-
console.log("getEncryptedChromeCookie results", results2);
|
|
54
|
-
}
|
|
55
|
-
return results2.filter((result) => result);
|
|
56
|
-
} catch (error) {
|
|
57
|
-
if (env.VERBOSE) {
|
|
58
|
-
console.log("error", error);
|
|
59
|
-
}
|
|
60
|
-
return [];
|
|
61
|
-
}
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
/**
|
|
65
|
-
*
|
|
66
|
-
* @param {string|undefined} name
|
|
67
|
-
* @param {string} domain
|
|
68
|
-
* @param {boolean} requireJwt
|
|
69
|
-
* @returns {Promise<[string]>}
|
|
70
|
-
*/
|
|
71
|
-
async function getChromeCookies({ name, domain = "%", requireJwt = false }) {
|
|
72
|
-
if (invalidString(name)) {
|
|
73
|
-
throw new Error("name must be a string");
|
|
74
|
-
}
|
|
75
|
-
if (invalidString(domain)) {
|
|
76
|
-
throw new Error("domain must be a string");
|
|
77
|
-
}
|
|
78
|
-
const encryptedDataItems = await getPromise(name, domain);
|
|
79
|
-
const password = await getChromePassword();
|
|
80
|
-
const decrypted = encryptedDataItems
|
|
81
|
-
.filter((encryptedData) => {
|
|
82
|
-
return encryptedData != null && encryptedData.length > 0;
|
|
83
|
-
})
|
|
84
|
-
.map(async (encryptedData) => {
|
|
85
|
-
if (env.VERBOSE) {
|
|
86
|
-
console.log("Received encrypted", encryptedData);
|
|
87
|
-
}
|
|
88
|
-
let d;
|
|
89
|
-
try {
|
|
90
|
-
d = await decrypt(password, encryptedData);
|
|
91
|
-
} catch (e) {
|
|
92
|
-
if (env.VERBOSE) {
|
|
93
|
-
console.log("Error decrypting cookie", e);
|
|
94
|
-
}
|
|
95
|
-
return null;
|
|
96
|
-
}
|
|
97
|
-
if (d) {
|
|
98
|
-
if (env.VERBOSE) {
|
|
99
|
-
console.log("Decrypted", d);
|
|
100
|
-
}
|
|
101
|
-
return d;
|
|
102
|
-
}
|
|
103
|
-
return null;
|
|
104
|
-
});
|
|
105
|
-
const results = await Promise.all(decrypted);
|
|
106
|
-
if (env.VERBOSE) {
|
|
107
|
-
console.log("results", results);
|
|
108
|
-
}
|
|
109
|
-
return results.map(toStringOrNull);
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
const chromeLocal = path.join(
|
|
113
|
-
HOME,
|
|
114
|
-
"Library",
|
|
115
|
-
"Application Support",
|
|
116
|
-
"Google",
|
|
117
|
-
"Chrome"
|
|
118
|
-
);
|
|
119
|
-
|
|
120
|
-
async function getEncryptedChromeCookie({
|
|
121
|
-
name,
|
|
122
|
-
domain,
|
|
123
|
-
file = path.join(chromeLocal, "Default", "Cookies"),
|
|
124
|
-
}) {
|
|
125
|
-
if (name && typeof name !== "string") {
|
|
126
|
-
throw new Error("name must be a string");
|
|
127
|
-
}
|
|
128
|
-
if (domain && typeof domain !== "string") {
|
|
129
|
-
throw new Error("domain must be a string");
|
|
130
|
-
}
|
|
131
|
-
if (file && typeof file !== "string") {
|
|
132
|
-
throw new Error("file must be a string");
|
|
133
|
-
}
|
|
134
|
-
if (!existsSync(file)) {
|
|
135
|
-
throw new Error(`File ${file} does not exist`);
|
|
136
|
-
}
|
|
137
|
-
if (env.VERBOSE) {
|
|
138
|
-
const s = file.split("/").slice(-3).join("/");
|
|
139
|
-
console.log(`Trying Chrome (at ${s}) cookie ${name} for domain ${domain}`);
|
|
140
|
-
}
|
|
141
|
-
let sql;
|
|
142
|
-
sql = `SELECT encrypted_value FROM cookies`;
|
|
143
|
-
if (typeof name === "string" || typeof domain === "string") {
|
|
144
|
-
sql += ` WHERE `;
|
|
145
|
-
if (typeof name === "string") {
|
|
146
|
-
sql += `name = '${name}'`;
|
|
147
|
-
if (typeof domain === "string") {
|
|
148
|
-
sql += ` AND `;
|
|
149
|
-
}
|
|
150
|
-
}
|
|
151
|
-
if (typeof domain === "string") {
|
|
152
|
-
sql += `host_key LIKE '${domain}';`;
|
|
153
|
-
}
|
|
154
|
-
}
|
|
155
|
-
return doSqliteQuery1(file, sql);
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
/**
|
|
159
|
-
*
|
|
160
|
-
* @returns {Promise<string>}
|
|
161
|
-
*/
|
|
162
|
-
async function getChromePassword() {
|
|
163
|
-
return execSimple(
|
|
164
|
-
'security find-generic-password -w -s "Chrome Safe Storage"'
|
|
165
|
-
);
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
/**
|
|
169
|
-
*
|
|
170
|
-
* @param {string} password
|
|
171
|
-
* @param {Buffer} encryptedData
|
|
172
|
-
* @returns {Promise<string>}
|
|
173
|
-
*/
|
|
174
|
-
async function decrypt(password, encryptedData) {
|
|
175
|
-
if (typeof password !== "string") {
|
|
176
|
-
throw new Error("password must be a string: " + password);
|
|
177
|
-
}
|
|
178
|
-
let encryptedData1;
|
|
179
|
-
encryptedData1 = encryptedData;
|
|
180
|
-
if (encryptedData1 == null || typeof encryptedData1 !== "object") {
|
|
181
|
-
throw new Error("encryptedData must be a object: " + encryptedData1);
|
|
182
|
-
}
|
|
183
|
-
if (!(encryptedData1 instanceof Buffer)) {
|
|
184
|
-
if (Array.isArray(encryptedData1) && encryptedData1[0] instanceof Buffer) {
|
|
185
|
-
[encryptedData1] = encryptedData1;
|
|
186
|
-
if (env.VERBOSE) {
|
|
187
|
-
console.log(
|
|
188
|
-
`encryptedData is an array of buffers, selected first: ${encryptedData1}`
|
|
189
|
-
);
|
|
190
|
-
}
|
|
191
|
-
} else {
|
|
192
|
-
throw new Error("encryptedData must be a Buffer: " + encryptedData1);
|
|
193
|
-
}
|
|
194
|
-
encryptedData1 = Buffer.from(encryptedData1);
|
|
195
|
-
}
|
|
196
|
-
if (env.VERBOSE) {
|
|
197
|
-
console.log(`Trying to decrypt with password ${password}`);
|
|
198
|
-
}
|
|
199
|
-
return new Promise((resolve, reject) => {
|
|
200
|
-
crypto.pbkdf2(password, "saltysalt", 1003, 16, "sha1", (error, buffer) => {
|
|
201
|
-
try {
|
|
202
|
-
if (error) {
|
|
203
|
-
if (env.VERBOSE) {
|
|
204
|
-
console.log("Error doing pbkdf2", error);
|
|
205
|
-
}
|
|
206
|
-
reject(error);
|
|
207
|
-
return;
|
|
208
|
-
}
|
|
209
|
-
|
|
210
|
-
if (buffer.length !== 16) {
|
|
211
|
-
if (env.VERBOSE) {
|
|
212
|
-
console.log(
|
|
213
|
-
"Error doing pbkdf2, buffer length is not 16",
|
|
214
|
-
buffer.length
|
|
215
|
-
);
|
|
216
|
-
}
|
|
217
|
-
reject(new Error("Buffer length is not 16"));
|
|
218
|
-
return;
|
|
219
|
-
}
|
|
220
|
-
|
|
221
|
-
const iv = new Buffer.from(new Array(17).join(" "), "binary");
|
|
222
|
-
const decipher = crypto.createDecipheriv("aes-128-cbc", buffer, iv);
|
|
223
|
-
decipher.setAutoPadding(false);
|
|
224
|
-
|
|
225
|
-
if (encryptedData1 && encryptedData1.slice) {
|
|
226
|
-
encryptedData1 = encryptedData1.slice(3);
|
|
227
|
-
}
|
|
228
|
-
|
|
229
|
-
if (encryptedData1.length % 16 !== 0) {
|
|
230
|
-
if (env.VERBOSE) {
|
|
231
|
-
console.log(
|
|
232
|
-
"Error doing pbkdf2, encryptedData length is not a multiple of 16",
|
|
233
|
-
encryptedData1.length
|
|
234
|
-
);
|
|
235
|
-
}
|
|
236
|
-
reject(new Error("encryptedData length is not a multiple of 16"));
|
|
237
|
-
return;
|
|
238
|
-
}
|
|
239
|
-
|
|
240
|
-
let decoded = decipher.update(encryptedData1);
|
|
241
|
-
try {
|
|
242
|
-
decipher.final("utf-8");
|
|
243
|
-
} catch (e) {
|
|
244
|
-
if (env.VERBOSE) {
|
|
245
|
-
console.log("Error doing decipher.final()", e);
|
|
246
|
-
}
|
|
247
|
-
reject(e);
|
|
248
|
-
return;
|
|
249
|
-
}
|
|
250
|
-
|
|
251
|
-
const padding = decoded[decoded.length - 1];
|
|
252
|
-
if (padding) {
|
|
253
|
-
decoded = decoded.slice(0, 0 - padding);
|
|
254
|
-
}
|
|
255
|
-
// noinspection JSCheckFunctionSignatures
|
|
256
|
-
decoded = decoded.toString("utf8");
|
|
257
|
-
resolve(decoded);
|
|
258
|
-
} catch (e) {
|
|
259
|
-
reject(e);
|
|
260
|
-
}
|
|
261
|
-
});
|
|
262
|
-
});
|
|
263
|
-
}
|