@mherod/get-cookie 2.0.0-rc.3 → 2.0.0-rc.30
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/runConfigurations/build.xml +12 -0
- package/.parcelrc +12 -0
- package/.prettierignore +5 -0
- package/.prettierrc +12 -0
- package/.terserrc +26 -0
- package/README.md +2 -2
- package/dist/cli.js +2 -0
- package/dist/index.js +2 -687
- package/dist/index.js.map +1 -0
- package/dist/module.js +1323 -0
- package/dist/module.js.map +1 -0
- package/dist/prompt.2b8c61c0.js +40 -0
- package/dist/prompt.536a2c51.js +40 -0
- package/dist/prompt.fb2c7dad.js.map +1 -0
- package/dist/types.d.ts +25 -0
- package/dist/types.d.ts.map +1 -0
- package/jest.config.ts +14 -0
- package/package-lock.json +2688 -6684
- package/package.json +42 -35
- package/src/CookieRow.ts +1 -0
- package/src/CookieSpec.ts +3 -1
- package/src/CookieStore.ts +27 -0
- package/src/ExportedCookie.ts +13 -0
- package/src/FetchResponse.ts +1 -2
- package/src/FileCookieStore.ts +175 -0
- package/src/StringToRegex.ts +16 -0
- package/src/argv.ts +29 -0
- package/src/browsers/ChromeApplicationSupport.ts +10 -0
- package/src/browsers/ChromeCookieQueryStrategy.ts +71 -131
- package/src/browsers/CompositeCookieQueryStrategy.ts +35 -11
- package/src/browsers/CookieQueryStrategy.ts +2 -0
- package/src/browsers/CookieStoreQueryStrategy.ts +99 -0
- package/src/browsers/DoSqliteQueryWithTransform.ts +85 -0
- package/src/browsers/FirefoxCookieQueryStrategy.ts +12 -7
- package/src/browsers/SafariCookieQueryStrategy.ts +3 -0
- package/src/browsers/decrypt.ts +118 -0
- package/src/browsers/getChromePassword.ts +9 -0
- package/src/cli.ts +52 -36
- package/src/comboQueryCookieSpec.ts +24 -0
- package/src/cookieSpecsFromUrl.ts +26 -0
- package/src/execSimple.ts +13 -0
- package/src/fetchWithCookies.ts +105 -38
- package/src/findAllFiles.ts +26 -54
- package/src/getChromeCookie.ts +19 -0
- package/src/getCookie.ts +20 -0
- package/src/getFirefoxCookie.ts +19 -0
- package/src/getGroupedRenderedCookies.ts +11 -24
- package/src/getMergedRenderedCookies.ts +12 -0
- package/src/global.ts +1 -1
- package/src/index.ts +14 -58
- package/src/isValidJwt.ts +4 -4
- package/src/listChromeProfiles.ts +45 -0
- package/src/logger.ts +3 -0
- package/src/queryCookies.ts +20 -11
- package/src/resultsRendered.ts +6 -3
- package/src/util/flatMapAsync.test.ts +55 -0
- package/src/util/flatMapAsync.ts +37 -0
- package/tsconfig.json +12 -16
- package/.github/dependabot.yml +0 -6
- package/.prettierrc.json +0 -1
- package/src/IsExportedCookie.ts +0 -9
- package/src/MemoryCookieStore.ts +0 -5
- package/src/browsers/MemoryCookieJarQueryStrategy.ts +0 -53
- package/src/doSqliteQuery1.ts +0 -51
- package/src/utils.ts +0 -50
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
import { BinaryLike, createDecipheriv, pbkdf2 } from "crypto";
|
|
2
|
+
import { parsedArgs } from "../argv";
|
|
3
|
+
import consola from "consola";
|
|
4
|
+
|
|
5
|
+
// Function to decrypt encrypted data using a password
|
|
6
|
+
export async function decrypt(
|
|
7
|
+
password: BinaryLike, // The password to use for decryption
|
|
8
|
+
encryptedData: Buffer // The data to decrypt
|
|
9
|
+
): Promise<string> {
|
|
10
|
+
// Returns a promise that resolves with the decrypted string
|
|
11
|
+
// Check if password is a string
|
|
12
|
+
if (typeof password !== "string") {
|
|
13
|
+
throw new Error("password must be a string: " + password);
|
|
14
|
+
}
|
|
15
|
+
let encryptedData1: any;
|
|
16
|
+
encryptedData1 = encryptedData;
|
|
17
|
+
// Check if encryptedData is an object
|
|
18
|
+
if (encryptedData1 == null || typeof encryptedData1 !== "object") {
|
|
19
|
+
throw new Error("encryptedData must be a object: " + encryptedData1);
|
|
20
|
+
}
|
|
21
|
+
// Check if encryptedData is a Buffer or an array of Buffers
|
|
22
|
+
if (!(encryptedData1 instanceof Buffer)) {
|
|
23
|
+
if (Array.isArray(encryptedData1) && encryptedData1[0] instanceof Buffer) {
|
|
24
|
+
[encryptedData1] = encryptedData1;
|
|
25
|
+
// Log if encryptedData is an array of buffers
|
|
26
|
+
if (parsedArgs.verbose) {
|
|
27
|
+
console.log(
|
|
28
|
+
`encryptedData is an array of buffers, selected first: ${encryptedData1}`
|
|
29
|
+
);
|
|
30
|
+
}
|
|
31
|
+
} else {
|
|
32
|
+
throw new Error("encryptedData must be a Buffer: " + encryptedData1);
|
|
33
|
+
}
|
|
34
|
+
encryptedData1 = Buffer.from(encryptedData1);
|
|
35
|
+
}
|
|
36
|
+
// Log the password being used for decryption
|
|
37
|
+
if (parsedArgs.verbose) {
|
|
38
|
+
consola.start(`Trying to decrypt with password: ${password}`);
|
|
39
|
+
}
|
|
40
|
+
// Return a promise that resolves with the decrypted string
|
|
41
|
+
return new Promise((resolve, reject) => {
|
|
42
|
+
// Use pbkdf2 to derive a key from the password
|
|
43
|
+
pbkdf2(password, "saltysalt", 1003, 16, "sha1", (error, buffer) => {
|
|
44
|
+
try {
|
|
45
|
+
// Handle any errors from pbkdf2
|
|
46
|
+
if (error) {
|
|
47
|
+
if (parsedArgs.verbose) {
|
|
48
|
+
console.log("Error doing pbkdf2", error);
|
|
49
|
+
}
|
|
50
|
+
reject(error);
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
// Check if the buffer length is 16
|
|
55
|
+
if (buffer.length !== 16) {
|
|
56
|
+
if (parsedArgs.verbose) {
|
|
57
|
+
console.log(
|
|
58
|
+
"Error doing pbkdf2, buffer length is not 16",
|
|
59
|
+
buffer.length
|
|
60
|
+
);
|
|
61
|
+
}
|
|
62
|
+
reject(new Error("Buffer length is not 16"));
|
|
63
|
+
return;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// Create an initialization vector
|
|
67
|
+
const str = new Array(17).join(" ");
|
|
68
|
+
const iv = Buffer.from(str, "binary");
|
|
69
|
+
// Create a decipher using the derived key and initialization vector
|
|
70
|
+
const decipher = createDecipheriv("aes-128-cbc", buffer, iv);
|
|
71
|
+
decipher.setAutoPadding(false);
|
|
72
|
+
|
|
73
|
+
// Remove the first 3 bytes from the encrypted data
|
|
74
|
+
if (encryptedData1 && encryptedData1.slice) {
|
|
75
|
+
encryptedData1 = encryptedData1.slice(3);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
// Check if the encrypted data length is a multiple of 16
|
|
79
|
+
if (encryptedData1.length % 16 !== 0) {
|
|
80
|
+
if (parsedArgs.verbose) {
|
|
81
|
+
console.log(
|
|
82
|
+
"Error doing pbkdf2, encryptedData length is not a multiple of 16",
|
|
83
|
+
encryptedData1.length
|
|
84
|
+
);
|
|
85
|
+
}
|
|
86
|
+
reject(new Error("encryptedData length is not a multiple of 16"));
|
|
87
|
+
return;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
// Update the decipher with the encrypted data
|
|
91
|
+
let decoded = decipher.update(encryptedData1);
|
|
92
|
+
try {
|
|
93
|
+
// Finalize the decipher
|
|
94
|
+
decipher.final("utf-8");
|
|
95
|
+
} catch (e) {
|
|
96
|
+
if (parsedArgs.verbose) {
|
|
97
|
+
console.log("Error doing decipher.final()", e);
|
|
98
|
+
}
|
|
99
|
+
reject(e);
|
|
100
|
+
return;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
// Remove padding from the decoded data
|
|
104
|
+
const padding = decoded[decoded.length - 1];
|
|
105
|
+
if (padding) {
|
|
106
|
+
decoded = decoded.slice(0, 0 - padding);
|
|
107
|
+
}
|
|
108
|
+
// Convert the decoded data to a string
|
|
109
|
+
const decodedString = decoded.toString("utf8");
|
|
110
|
+
// Resolve the promise with the decrypted string
|
|
111
|
+
resolve(decodedString);
|
|
112
|
+
} catch (e) {
|
|
113
|
+
// Reject the promise if there is an error
|
|
114
|
+
reject(e);
|
|
115
|
+
}
|
|
116
|
+
});
|
|
117
|
+
});
|
|
118
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { execSimple } from "../execSimple";
|
|
2
|
+
|
|
3
|
+
const chromePassword: Promise<string> = execSimple(
|
|
4
|
+
'security find-generic-password -w -s "Chrome Safe Storage"'
|
|
5
|
+
);
|
|
6
|
+
|
|
7
|
+
export async function getChromePassword(): Promise<string> {
|
|
8
|
+
return await chromePassword;
|
|
9
|
+
}
|
package/src/cli.ts
CHANGED
|
@@ -1,31 +1,30 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
1
|
+
#!/usr/bin/env ts-node
|
|
2
2
|
|
|
3
|
-
import
|
|
4
|
-
import { argv } from "./argv";
|
|
5
|
-
import { queryCookies } from "./queryCookies";
|
|
3
|
+
import { argv, parsedArgs } from "./argv";
|
|
6
4
|
import { groupBy } from "lodash";
|
|
7
5
|
import { green, red, yellow } from "colorette";
|
|
8
6
|
import { resultsRendered } from "./resultsRendered";
|
|
9
7
|
import { fetchWithCookies } from "./fetchWithCookies";
|
|
10
8
|
import { unpackHeaders } from "./unpackHeaders";
|
|
11
9
|
import CookieSpec from "./CookieSpec";
|
|
10
|
+
import { comboQueryCookieSpec } from "./comboQueryCookieSpec";
|
|
11
|
+
import { cookieSpecsFromUrl } from "./cookieSpecsFromUrl";
|
|
12
|
+
import logger from "./logger";
|
|
12
13
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
async function cliQueryCookies({ name, domain }: CookieSpec) {
|
|
14
|
+
async function cliQueryCookies(cookieSpec: CookieSpec | CookieSpec[]) {
|
|
16
15
|
try {
|
|
17
|
-
const results = await
|
|
16
|
+
const results = await comboQueryCookieSpec(cookieSpec);
|
|
18
17
|
if (results == null || results.length == 0) {
|
|
19
|
-
|
|
18
|
+
logger.error(red("No results"));
|
|
20
19
|
return;
|
|
21
20
|
}
|
|
22
21
|
if (parsedArgs["dump"] || parsedArgs["d"]) {
|
|
23
|
-
|
|
22
|
+
logger.log(results);
|
|
24
23
|
return;
|
|
25
24
|
}
|
|
26
25
|
if (parsedArgs["dump-grouped"] || parsedArgs["D"]) {
|
|
27
26
|
const groupedByFile = groupBy(results, (r) => r.meta?.file);
|
|
28
|
-
|
|
27
|
+
logger.log(green(JSON.stringify(groupedByFile, null, 2)));
|
|
29
28
|
return;
|
|
30
29
|
}
|
|
31
30
|
if (
|
|
@@ -33,62 +32,65 @@ async function cliQueryCookies({ name, domain }: CookieSpec) {
|
|
|
33
32
|
parsedArgs["render-merged"] ||
|
|
34
33
|
parsedArgs["r"]
|
|
35
34
|
) {
|
|
36
|
-
|
|
35
|
+
logger.log(yellow(resultsRendered(results)));
|
|
37
36
|
return;
|
|
38
37
|
}
|
|
39
38
|
if (parsedArgs["render-grouped"] || parsedArgs["R"]) {
|
|
40
39
|
const groupedByFile = groupBy(results, (r) => r.meta?.file);
|
|
41
40
|
for (const file of Object.keys(groupedByFile)) {
|
|
42
41
|
let results = groupedByFile[file];
|
|
43
|
-
|
|
42
|
+
logger.log(green(file) + ": ", yellow(resultsRendered(results)));
|
|
44
43
|
}
|
|
45
44
|
return;
|
|
46
45
|
}
|
|
47
46
|
for (const result of results) {
|
|
48
|
-
|
|
47
|
+
logger.log(result.value);
|
|
49
48
|
}
|
|
50
49
|
} catch (e) {
|
|
51
|
-
|
|
50
|
+
logger.error(e);
|
|
52
51
|
}
|
|
53
52
|
}
|
|
54
53
|
|
|
55
|
-
function main() {
|
|
54
|
+
async function main() {
|
|
56
55
|
if (parsedArgs["help"] || parsedArgs["h"]) {
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
56
|
+
logger.log(`Usage: ${argv[1]} [name] [domain] [options] `);
|
|
57
|
+
logger.log(`Options:`);
|
|
58
|
+
logger.log(` -h, --help: Show this help`);
|
|
59
|
+
logger.log(` -v, --verbose: Show verbose output`);
|
|
60
|
+
logger.log(` -d, --dump: Dump all results`);
|
|
61
|
+
logger.log(` -D, --dump-grouped: Dump all results, grouped by profile`);
|
|
62
|
+
logger.log(` -r, --render: Render all results`);
|
|
64
63
|
return;
|
|
65
64
|
}
|
|
66
65
|
|
|
66
|
+
parsedArgs["verbose"] = parsedArgs["verbose"] || parsedArgs["v"];
|
|
67
|
+
|
|
67
68
|
const fetchUrl: string = parsedArgs["fetch"] || parsedArgs["F"];
|
|
68
69
|
if (fetchUrl) {
|
|
69
70
|
let url: URL;
|
|
70
71
|
try {
|
|
71
72
|
url = new URL(<string>fetchUrl);
|
|
72
73
|
} catch (e) {
|
|
73
|
-
|
|
74
|
+
logger.error("Invalid URL", fetchUrl);
|
|
74
75
|
return;
|
|
75
76
|
}
|
|
77
|
+
logger.start("Fetching", url.href);
|
|
76
78
|
const headerArgs: string[] | string = parsedArgs["H"];
|
|
77
79
|
const headers = unpackHeaders(headerArgs);
|
|
78
80
|
const onfulfilled = (res: Response) => {
|
|
79
81
|
if (parsedArgs["dump-response-headers"]) {
|
|
80
82
|
res.headers.forEach((value: string, key: string) => {
|
|
81
|
-
|
|
83
|
+
logger.log(`${key}: ${value}`);
|
|
82
84
|
});
|
|
83
85
|
}
|
|
84
86
|
if (parsedArgs["dump-response-body"]) {
|
|
85
87
|
res.text().then((r) => {
|
|
86
|
-
|
|
88
|
+
logger.log(r);
|
|
87
89
|
});
|
|
88
90
|
}
|
|
89
91
|
return;
|
|
90
92
|
};
|
|
91
|
-
fetchWithCookies(
|
|
93
|
+
return fetchWithCookies(
|
|
92
94
|
url,
|
|
93
95
|
{
|
|
94
96
|
//
|
|
@@ -96,19 +98,33 @@ function main() {
|
|
|
96
98
|
}
|
|
97
99
|
//
|
|
98
100
|
).then(
|
|
99
|
-
|
|
100
|
-
|
|
101
|
+
(res) => {
|
|
102
|
+
logger.debug("Response", res);
|
|
103
|
+
onfulfilled(res);
|
|
104
|
+
},
|
|
105
|
+
logger.error
|
|
101
106
|
//
|
|
102
107
|
);
|
|
103
|
-
return;
|
|
104
108
|
}
|
|
105
109
|
|
|
106
|
-
const
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
+
const cookieSpecs: CookieSpec[] = [];
|
|
111
|
+
const argUrl: string = parsedArgs["url"] || parsedArgs["u"];
|
|
112
|
+
if (argUrl) {
|
|
113
|
+
for (const cookieSpec of cookieSpecsFromUrl(argUrl)) {
|
|
114
|
+
cookieSpecs.push(cookieSpec);
|
|
115
|
+
}
|
|
116
|
+
} else {
|
|
117
|
+
cookieSpecs.push({
|
|
118
|
+
name: parsedArgs["name"] || parsedArgs["_"][0] || "%",
|
|
119
|
+
domain: parsedArgs["domain"] || parsedArgs["_"][1] || "%",
|
|
120
|
+
});
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
if (parsedArgs.verbose) {
|
|
124
|
+
logger.log("cookieSpecs", cookieSpecs);
|
|
125
|
+
}
|
|
110
126
|
|
|
111
|
-
cliQueryCookies(
|
|
127
|
+
await cliQueryCookies(cookieSpecs).catch(logger.error);
|
|
112
128
|
}
|
|
113
129
|
|
|
114
|
-
main();
|
|
130
|
+
main().then((r) => r, logger.error);
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { MultiCookieSpec } from "./CookieSpec";
|
|
2
|
+
import ExportedCookie from "./ExportedCookie";
|
|
3
|
+
import { queryCookies } from "./queryCookies";
|
|
4
|
+
import { uniqBy } from "lodash";
|
|
5
|
+
|
|
6
|
+
export async function comboQueryCookieSpec(
|
|
7
|
+
cookieSpec: MultiCookieSpec
|
|
8
|
+
): Promise<ExportedCookie[]> {
|
|
9
|
+
const cookies: ExportedCookie[] = [];
|
|
10
|
+
if (Array.isArray(cookieSpec)) {
|
|
11
|
+
const results: Awaited<ExportedCookie[]>[] = await Promise.all(
|
|
12
|
+
cookieSpec.map((cs) => {
|
|
13
|
+
return queryCookies(cs);
|
|
14
|
+
})
|
|
15
|
+
);
|
|
16
|
+
for (const exportedCookie of results.flat()) {
|
|
17
|
+
cookies.push(exportedCookie);
|
|
18
|
+
}
|
|
19
|
+
} else {
|
|
20
|
+
const singleQuery: ExportedCookie[] = await queryCookies(cookieSpec);
|
|
21
|
+
cookies.push(...singleQuery);
|
|
22
|
+
}
|
|
23
|
+
return uniqBy(cookies, JSON.stringify);
|
|
24
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import CookieSpec from "./CookieSpec";
|
|
2
|
+
import { uniqBy } from "lodash";
|
|
3
|
+
|
|
4
|
+
export function cookieSpecsFromUrl(url: URL | string): CookieSpec[] {
|
|
5
|
+
const url1 = typeof url == "string" ? new URL(url) : url;
|
|
6
|
+
const cookieSpecs = [];
|
|
7
|
+
const splits = url1.hostname.split(".");
|
|
8
|
+
const tld = splits.slice(-2).join(".");
|
|
9
|
+
const cookieSpec: CookieSpec = {
|
|
10
|
+
name: "%",
|
|
11
|
+
domain: "%." + tld,
|
|
12
|
+
};
|
|
13
|
+
cookieSpecs.push(cookieSpec);
|
|
14
|
+
const cookieSpec1: CookieSpec = {
|
|
15
|
+
name: "%",
|
|
16
|
+
domain: url1.hostname,
|
|
17
|
+
};
|
|
18
|
+
cookieSpecs.push(cookieSpec1);
|
|
19
|
+
// const isWww = splits.slice(-3)[0] === "www";
|
|
20
|
+
const cookieSpec2: CookieSpec = {
|
|
21
|
+
name: "%",
|
|
22
|
+
domain: tld,
|
|
23
|
+
};
|
|
24
|
+
cookieSpecs.push(cookieSpec2);
|
|
25
|
+
return uniqBy(cookieSpecs, JSON.stringify);
|
|
26
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { execSync } from "child_process";
|
|
2
|
+
|
|
3
|
+
export async function execSimple(command: string): Promise<string> {
|
|
4
|
+
try {
|
|
5
|
+
const stdout = execSync(command, {
|
|
6
|
+
encoding: "binary",
|
|
7
|
+
maxBuffer: 5 * 1024,
|
|
8
|
+
});
|
|
9
|
+
return stdout.trim();
|
|
10
|
+
} catch (error) {
|
|
11
|
+
throw error;
|
|
12
|
+
}
|
|
13
|
+
}
|
package/src/fetchWithCookies.ts
CHANGED
|
@@ -1,62 +1,129 @@
|
|
|
1
|
-
// noinspection JSUnusedGlobalSymbols
|
|
1
|
+
// noinspection JSUnusedGlobalSymbols,ExceptionCaughtLocallyJS
|
|
2
2
|
|
|
3
3
|
import { fetch as fetchImpl } from "cross-fetch";
|
|
4
4
|
import { merge } from "lodash";
|
|
5
5
|
// noinspection SpellCheckingInspection
|
|
6
6
|
import destr from "destr";
|
|
7
|
+
import { cookieJarPromise } from "./CookieStore";
|
|
8
|
+
import UserAgent from "user-agents";
|
|
9
|
+
import { parsedArgs } from "./argv";
|
|
10
|
+
import { blue, redBright, yellow } from "colorette";
|
|
11
|
+
import { getMergedRenderedCookies } from "./getMergedRenderedCookies";
|
|
12
|
+
import { cookieSpecsFromUrl } from "./cookieSpecsFromUrl";
|
|
7
13
|
import CookieSpec from "./CookieSpec";
|
|
8
|
-
import
|
|
9
|
-
|
|
14
|
+
import consola from "consola";
|
|
15
|
+
|
|
16
|
+
if (typeof fetchImpl !== "function") {
|
|
17
|
+
consola.error("fetch is not a function");
|
|
18
|
+
throw new Error("fetch is not a function");
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
const userAgent = new UserAgent().toString();
|
|
22
|
+
|
|
23
|
+
interface FetchRequestInit {
|
|
24
|
+
url: RequestInfo | URL | string;
|
|
25
|
+
options?: RequestInit;
|
|
26
|
+
}
|
|
10
27
|
|
|
11
28
|
export async function fetchWithCookies(
|
|
12
|
-
url: RequestInfo | URL,
|
|
29
|
+
url: RequestInfo | URL | string,
|
|
13
30
|
options: RequestInit | undefined = {},
|
|
14
|
-
fetch: Function = fetchImpl
|
|
31
|
+
fetch: Function = fetchImpl as Function,
|
|
32
|
+
originalRequest: FetchRequestInit | undefined = undefined
|
|
15
33
|
): Promise<Response> {
|
|
34
|
+
if (typeof fetch !== "function") {
|
|
35
|
+
const message = "fetch is not a function";
|
|
36
|
+
consola.error(message);
|
|
37
|
+
throw new Error(message);
|
|
38
|
+
}
|
|
39
|
+
const originalRequest1 = originalRequest || { url, options };
|
|
40
|
+
const headers: HeadersInit = {
|
|
41
|
+
"User-Agent": userAgent,
|
|
42
|
+
};
|
|
16
43
|
const defaultOptions: RequestInit = {
|
|
17
|
-
headers
|
|
18
|
-
"User-Agent":
|
|
19
|
-
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.88 Safari/537.36",
|
|
20
|
-
},
|
|
44
|
+
headers,
|
|
21
45
|
redirect: "manual",
|
|
22
46
|
};
|
|
23
47
|
const url2: string = `${url}`;
|
|
24
48
|
const url1: URL = new URL(url2);
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
const cookies: string[] = await getGroupedRenderedCookies(cookieSpec).catch(
|
|
33
|
-
() => []
|
|
49
|
+
consola.start("fetchWithCookies", url2);
|
|
50
|
+
const cookieSpecs: CookieSpec[] = cookieSpecsFromUrl(url1);
|
|
51
|
+
headers["Cookie"] = await getMergedRenderedCookies(cookieSpecs).catch(
|
|
52
|
+
(err) => {
|
|
53
|
+
consola.error(err);
|
|
54
|
+
return "";
|
|
55
|
+
}
|
|
34
56
|
);
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
headers:
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
});
|
|
57
|
+
if (parsedArgs["dump-request-headers"]) {
|
|
58
|
+
consola.info(redBright("Request URL:"), url1.href);
|
|
59
|
+
consola.info(blue("Request headers:"), headers);
|
|
60
|
+
}
|
|
61
|
+
const newOptions1: RequestInit = merge(defaultOptions, { headers }, options);
|
|
41
62
|
try {
|
|
42
|
-
const res: Response = await fetch(
|
|
63
|
+
const res: Response = await fetch(url1, newOptions1);
|
|
64
|
+
// noinspection JSMismatchedCollectionQueryUpdate
|
|
43
65
|
const headers: [string, string][] = [];
|
|
44
66
|
res.headers.forEach((value, key) => {
|
|
45
67
|
headers.push([key, value]);
|
|
46
68
|
});
|
|
47
|
-
for (const [key, value] of headers) {
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
69
|
+
// for (const [key, value] of headers) {
|
|
70
|
+
// if (key === "set-cookie") {
|
|
71
|
+
// const cookieJar1 = await cookieJarPromise;
|
|
72
|
+
// await cookieJar1.setCookie(value, url2);
|
|
73
|
+
// if (parsedArgs.verbose) {
|
|
74
|
+
// console.log(blue(`Set-Cookie:`), yellow(value), yellow(url2));
|
|
75
|
+
// }
|
|
76
|
+
// }
|
|
77
|
+
// }
|
|
78
|
+
|
|
79
|
+
const newUrl: string = res.headers.get("location") ?? res.url;
|
|
80
|
+
// const sameHost = new URL(newUrl).host === url1.host;
|
|
81
|
+
if (res.status == 301 || res.status == 302) {
|
|
82
|
+
// follow the redirect
|
|
83
|
+
if (newUrl && newUrl !== url2) {
|
|
84
|
+
if (parsedArgs.verbose || parsedArgs["dump-response-headers"]) {
|
|
85
|
+
console.log(blue(`Redirected to `), yellow(newUrl));
|
|
86
|
+
}
|
|
87
|
+
return fetchWithCookies(
|
|
88
|
+
//
|
|
89
|
+
newUrl,
|
|
90
|
+
newOptions1,
|
|
91
|
+
fetch,
|
|
92
|
+
originalRequest1
|
|
93
|
+
//
|
|
94
|
+
);
|
|
54
95
|
}
|
|
55
96
|
}
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
97
|
+
if (res.status == 303 && newUrl && newUrl !== url2) {
|
|
98
|
+
// follow the redirect with GET
|
|
99
|
+
let newOptions2: RequestInit = {};
|
|
100
|
+
switch (newOptions1.method) {
|
|
101
|
+
case "POST":
|
|
102
|
+
case "PUT":
|
|
103
|
+
case "DELETE":
|
|
104
|
+
merge(newOptions2, newOptions1, { method: "GET" });
|
|
105
|
+
newOptions2.body = undefined; // TODO: is this needed?
|
|
106
|
+
break;
|
|
107
|
+
case "HEAD":
|
|
108
|
+
case "GET":
|
|
109
|
+
merge(newOptions2, newOptions1);
|
|
110
|
+
newOptions2.body = undefined; // TODO: is this needed?
|
|
111
|
+
break;
|
|
112
|
+
default:
|
|
113
|
+
merge(newOptions2, newOptions1);
|
|
114
|
+
break;
|
|
115
|
+
}
|
|
116
|
+
if (parsedArgs.verbose) {
|
|
117
|
+
console.log(blue(`Redirected to `), yellow(newUrl));
|
|
118
|
+
}
|
|
119
|
+
return fetchWithCookies(
|
|
120
|
+
//
|
|
121
|
+
newUrl,
|
|
122
|
+
newOptions2,
|
|
123
|
+
fetch,
|
|
124
|
+
originalRequest1
|
|
125
|
+
//
|
|
126
|
+
);
|
|
60
127
|
}
|
|
61
128
|
|
|
62
129
|
const arrayBuffer1: Promise<ArrayBuffer> = res.arrayBuffer();
|
|
@@ -70,11 +137,11 @@ export async function fetchWithCookies(
|
|
|
70
137
|
}
|
|
71
138
|
|
|
72
139
|
async function text(): Promise<string> {
|
|
73
|
-
return buffer().then((buffer) => buffer.toString("utf8"));
|
|
140
|
+
return buffer().then((buffer: Buffer) => buffer.toString("utf8"));
|
|
74
141
|
}
|
|
75
142
|
|
|
76
143
|
async function json(): Promise<any> {
|
|
77
|
-
return text().then((text) => destr(text));
|
|
144
|
+
return text().then((text: string) => destr(text));
|
|
78
145
|
}
|
|
79
146
|
|
|
80
147
|
async function formData(): Promise<FormData> {
|
package/src/findAllFiles.ts
CHANGED
|
@@ -1,66 +1,38 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import
|
|
1
|
+
import { existsSync } from "fs";
|
|
2
|
+
import { parsedArgs } from "./argv";
|
|
3
|
+
import consola from "consola";
|
|
4
|
+
import { sync } from "fast-glob";
|
|
3
5
|
|
|
4
|
-
|
|
5
|
-
path,
|
|
6
|
-
name,
|
|
7
|
-
maxDepth = 2,
|
|
8
|
-
}: //
|
|
9
|
-
{
|
|
6
|
+
type FindFilesOptions = {
|
|
10
7
|
path: string;
|
|
11
8
|
name: string;
|
|
12
9
|
maxDepth?: number;
|
|
13
|
-
}
|
|
14
|
-
const rootSegments = path.split("/").length;
|
|
10
|
+
};
|
|
15
11
|
|
|
16
|
-
|
|
17
|
-
|
|
12
|
+
export function findAllFiles(
|
|
13
|
+
//
|
|
14
|
+
{ path, name, maxDepth = 2 }: FindFilesOptions
|
|
15
|
+
): //
|
|
16
|
+
string[] {
|
|
17
|
+
if (!existsSync(path)) {
|
|
18
|
+
throw new Error(`Path ${path} does not exist`);
|
|
18
19
|
}
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
readdirSync = fs.readdirSync(path);
|
|
23
|
-
} catch (e) {
|
|
24
|
-
if (env.VERBOSE) {
|
|
25
|
-
console.log(`Error reading ${path}`, e);
|
|
26
|
-
}
|
|
27
|
-
return [];
|
|
28
|
-
}
|
|
29
|
-
for (const file of readdirSync) {
|
|
30
|
-
const filePath = path + "/" + file;
|
|
31
|
-
let stat;
|
|
32
|
-
try {
|
|
33
|
-
stat = fs.statSync(filePath);
|
|
34
|
-
} catch (e) {
|
|
35
|
-
if (env.VERBOSE) {
|
|
36
|
-
console.error(`Error getting stat for ${filePath}`, e);
|
|
37
|
-
}
|
|
38
|
-
continue;
|
|
39
|
-
}
|
|
40
|
-
if (stat.isDirectory()) {
|
|
41
|
-
if (filePath.split("/").length < rootSegments + maxDepth) {
|
|
42
|
-
try {
|
|
43
|
-
const subFiles = await findAllFiles({
|
|
44
|
-
path: filePath,
|
|
45
|
-
name: name,
|
|
46
|
-
maxDepth: 2,
|
|
47
|
-
});
|
|
48
|
-
files.push(...subFiles);
|
|
49
|
-
} catch (e) {
|
|
50
|
-
if (env.VERBOSE) {
|
|
51
|
-
console.error(e);
|
|
52
|
-
}
|
|
53
|
-
}
|
|
54
|
-
}
|
|
55
|
-
} else if (file === name) {
|
|
56
|
-
files.push(filePath);
|
|
57
|
-
}
|
|
20
|
+
|
|
21
|
+
if (parsedArgs.verbose) {
|
|
22
|
+
consola.start(`Searching for ${name} files in ${path}`);
|
|
58
23
|
}
|
|
59
|
-
|
|
24
|
+
|
|
25
|
+
const files: string[] = sync(`${path}/**/${name}`, {
|
|
26
|
+
onlyFiles: true,
|
|
27
|
+
deep: maxDepth,
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
if (parsedArgs.verbose) {
|
|
60
31
|
if (files.length > 0) {
|
|
61
|
-
|
|
62
|
-
|
|
32
|
+
consola.success(`Found ${files.length} ${name} files`);
|
|
33
|
+
consola.info(files);
|
|
63
34
|
}
|
|
64
35
|
}
|
|
36
|
+
|
|
65
37
|
return files;
|
|
66
38
|
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import CookieSpec from "./CookieSpec";
|
|
2
|
+
import ExportedCookie from "./ExportedCookie";
|
|
3
|
+
import { queryCookies } from "./queryCookies";
|
|
4
|
+
import ChromeCookieQueryStrategy from "./browsers/ChromeCookieQueryStrategy";
|
|
5
|
+
import { isExportedCookie } from "./ExportedCookie";
|
|
6
|
+
|
|
7
|
+
export async function getChromeCookie(
|
|
8
|
+
params: CookieSpec
|
|
9
|
+
): Promise<ExportedCookie | undefined> {
|
|
10
|
+
const cookies = await queryCookies(
|
|
11
|
+
params,
|
|
12
|
+
new ChromeCookieQueryStrategy()
|
|
13
|
+
//
|
|
14
|
+
);
|
|
15
|
+
if (cookies.length == 0) {
|
|
16
|
+
throw new Error("Cookie not found");
|
|
17
|
+
}
|
|
18
|
+
return cookies.find(isExportedCookie);
|
|
19
|
+
}
|
package/src/getCookie.ts
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import CookieSpec from "./CookieSpec";
|
|
2
|
+
import ExportedCookie from "./ExportedCookie";
|
|
3
|
+
import { queryCookies } from "./queryCookies";
|
|
4
|
+
import CompositeCookieQueryStrategy from "./browsers/CompositeCookieQueryStrategy";
|
|
5
|
+
|
|
6
|
+
export async function getCookie(
|
|
7
|
+
params: CookieSpec
|
|
8
|
+
): Promise<ExportedCookie | undefined> {
|
|
9
|
+
//
|
|
10
|
+
const cookies = await queryCookies(
|
|
11
|
+
params,
|
|
12
|
+
new CompositeCookieQueryStrategy()
|
|
13
|
+
//
|
|
14
|
+
);
|
|
15
|
+
if (Array.isArray(cookies) && cookies.length > 0) {
|
|
16
|
+
return cookies.find((cookie) => cookie != null);
|
|
17
|
+
} else {
|
|
18
|
+
throw new Error("Cookie not found");
|
|
19
|
+
}
|
|
20
|
+
}
|