@shriyanss/js-recon 1.0.0 → 1.1.0-beta.2
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/.github/workflows/build-and-prettify.yaml +65 -0
- package/.github/workflows/npm-publish.yml +35 -0
- package/.prettierignore +2 -0
- package/.prettierrc +4 -0
- package/CHANGELOG.md +50 -0
- package/README.md +35 -139
- package/build/api_gateway/checkFeasibility.js +32 -0
- package/build/api_gateway/checkFeasibility.js.map +1 -0
- package/build/api_gateway/checkFireWallBlocking.js +24 -0
- package/build/api_gateway/checkFireWallBlocking.js.map +1 -0
- package/build/api_gateway/genReq.js +199 -0
- package/build/api_gateway/genReq.js.map +1 -0
- package/build/api_gateway/index.js +275 -0
- package/build/api_gateway/index.js.map +1 -0
- package/build/endpoints/gen_report/gen_json.js +22 -0
- package/build/endpoints/gen_report/gen_json.js.map +1 -0
- package/build/endpoints/gen_report/gen_markdown.js +66 -0
- package/build/endpoints/gen_report/gen_markdown.js.map +1 -0
- package/build/endpoints/gen_report/utility/iterate_n_store.js +46 -0
- package/build/endpoints/gen_report/utility/iterate_n_store.js.map +1 -0
- package/build/endpoints/index.js +89 -0
- package/build/endpoints/index.js.map +1 -0
- package/build/endpoints/next_js/client_jsFilesHref.js +91 -0
- package/build/endpoints/next_js/client_jsFilesHref.js.map +1 -0
- package/build/endpoints/next_js/client_jsonParse.js +78 -0
- package/build/endpoints/next_js/client_jsonParse.js.map +1 -0
- package/build/endpoints/next_js/client_subsequentRequests.js +199 -0
- package/build/endpoints/next_js/client_subsequentRequests.js.map +1 -0
- package/build/endpoints/next_js/getWebpacks.js +45 -0
- package/build/endpoints/next_js/getWebpacks.js.map +1 -0
- package/build/globalConfig.js +11 -0
- package/build/globalConfig.js.map +1 -0
- package/build/index.js +166 -0
- package/build/index.js.map +1 -0
- package/build/lazyLoad/downloadFilesUtil.js +128 -0
- package/build/lazyLoad/downloadFilesUtil.js.map +1 -0
- package/build/lazyLoad/downloadLoadedJsUtil.js +51 -0
- package/build/lazyLoad/downloadLoadedJsUtil.js.map +1 -0
- package/build/lazyLoad/globals.js +22 -0
- package/build/lazyLoad/globals.js.map +1 -0
- package/build/lazyLoad/index.js +170 -0
- package/build/lazyLoad/index.js.map +1 -0
- package/build/lazyLoad/next_js/next_GetJSScript.js +94 -0
- package/build/lazyLoad/next_js/next_GetJSScript.js.map +1 -0
- package/build/lazyLoad/next_js/next_GetLazyResources.js +202 -0
- package/build/lazyLoad/next_js/next_GetLazyResources.js.map +1 -0
- package/build/lazyLoad/next_js/next_SubsequentRequests.js +120 -0
- package/build/lazyLoad/next_js/next_SubsequentRequests.js.map +1 -0
- package/build/lazyLoad/nuxt_js/nuxt_astParse.js +188 -0
- package/build/lazyLoad/nuxt_js/nuxt_astParse.js.map +1 -0
- package/build/lazyLoad/nuxt_js/nuxt_getFromPageSource.js +75 -0
- package/build/lazyLoad/nuxt_js/nuxt_getFromPageSource.js.map +1 -0
- package/build/lazyLoad/nuxt_js/nuxt_stringAnalysisJSFiles.js +94 -0
- package/build/lazyLoad/nuxt_js/nuxt_stringAnalysisJSFiles.js.map +1 -0
- package/build/lazyLoad/svelte/svelte_getFromPageSource.js +68 -0
- package/build/lazyLoad/svelte/svelte_getFromPageSource.js.map +1 -0
- package/build/lazyLoad/svelte/svelte_stringAnalysisJSFiles.js +95 -0
- package/build/lazyLoad/svelte/svelte_stringAnalysisJSFiles.js.map +1 -0
- package/build/map/index.js +58 -0
- package/build/map/index.js.map +1 -0
- package/build/map/next_js/getFetchInstances.js +108 -0
- package/build/map/next_js/getFetchInstances.js.map +1 -0
- package/build/map/next_js/getWebpackConnections.js +227 -0
- package/build/map/next_js/getWebpackConnections.js.map +1 -0
- package/build/map/next_js/interactive.js +32 -0
- package/build/map/next_js/interactive.js.map +1 -0
- package/build/map/next_js/interactive_helpers/commandHandler.js +190 -0
- package/build/map/next_js/interactive_helpers/commandHandler.js.map +1 -0
- package/build/map/next_js/interactive_helpers/commandHelpers.js +91 -0
- package/build/map/next_js/interactive_helpers/commandHelpers.js.map +1 -0
- package/build/map/next_js/interactive_helpers/helpMenu.js +11 -0
- package/build/map/next_js/interactive_helpers/helpMenu.js.map +1 -0
- package/build/map/next_js/interactive_helpers/keybindings.js +80 -0
- package/build/map/next_js/interactive_helpers/keybindings.js.map +1 -0
- package/build/map/next_js/interactive_helpers/printer.js +17 -0
- package/build/map/next_js/interactive_helpers/printer.js.map +1 -0
- package/build/map/next_js/interactive_helpers/ui.js +81 -0
- package/build/map/next_js/interactive_helpers/ui.js.map +1 -0
- package/build/map/next_js/resolveFetch.js +201 -0
- package/build/map/next_js/resolveFetch.js.map +1 -0
- package/build/run/index.js +62 -0
- package/build/run/index.js.map +1 -0
- package/build/strings/index.js +238 -0
- package/build/strings/index.js.map +1 -0
- package/build/strings/openapi.js +55 -0
- package/build/strings/openapi.js.map +1 -0
- package/build/strings/permutate.js +55 -0
- package/build/strings/permutate.js.map +1 -0
- package/build/strings/secrets.js +89 -0
- package/build/strings/secrets.js.map +1 -0
- package/build/techDetect/index.js +229 -0
- package/build/techDetect/index.js.map +1 -0
- package/build/utility/ai.js +69 -0
- package/build/utility/ai.js.map +1 -0
- package/build/utility/globals.js +84 -0
- package/build/utility/globals.js.map +1 -0
- package/build/utility/interfaces.js +2 -0
- package/build/utility/interfaces.js.map +1 -0
- package/build/utility/makeReq.js +265 -0
- package/build/utility/makeReq.js.map +1 -0
- package/build/utility/resolvePath.js +44 -0
- package/build/utility/resolvePath.js.map +1 -0
- package/{utility → build/utility}/runSandboxed.js +10 -13
- package/build/utility/runSandboxed.js.map +1 -0
- package/{utility → build/utility}/urlUtils.js +9 -11
- package/build/utility/urlUtils.js.map +1 -0
- package/docs/CNAME +1 -0
- package/docs/README.md +20 -0
- package/docs/api-gateway.md +68 -0
- package/docs/endpoints.md +49 -0
- package/docs/example-scenario.md +258 -0
- package/docs/interactive-mode.md +76 -0
- package/docs/lazyload.md +56 -0
- package/docs/map.md +53 -0
- package/docs/run.md +54 -0
- package/docs/strings.md +75 -0
- package/package.json +50 -38
- package/api_gateway/checkFeasibility.js +0 -25
- package/api_gateway/checkFireWallBlocking.js +0 -17
- package/api_gateway/genReq.js +0 -214
- package/api_gateway/index.js +0 -325
- package/endpoints/index.js +0 -7
- package/globalConfig.js +0 -12
- package/index.js +0 -69
- package/lazyLoad/downloadFilesUtil.js +0 -122
- package/lazyLoad/downloadLoadedJsUtil.js +0 -54
- package/lazyLoad/globals.js +0 -15
- package/lazyLoad/index.js +0 -167
- package/lazyLoad/next_js/next_GetJSScript.js +0 -99
- package/lazyLoad/next_js/next_GetLazyResources.js +0 -201
- package/lazyLoad/next_js/next_SubsequentRequests.js +0 -138
- package/lazyLoad/nuxt_js/nuxt_astParse.js +0 -194
- package/lazyLoad/nuxt_js/nuxt_getFromPageSource.js +0 -77
- package/lazyLoad/nuxt_js/nuxt_stringAnalysisJSFiles.js +0 -99
- package/research/firewall_bypass.md +0 -38
- package/research/next_js.md +0 -116
- package/research/nuxt_js.md +0 -125
- package/research/vue_js.md +0 -9
- package/strings/index.js +0 -145
- package/techDetect/index.js +0 -156
- package/utility/globals.js +0 -6
- package/utility/makeReq.js +0 -179
- package/utility/resolvePath.js +0 -43
package/globalConfig.js
DELETED
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
const githubURL = "https://github.com/shriyanss/js-recon"
|
|
2
|
-
const version = "1.0.0";
|
|
3
|
-
const toolDesc = "JS Recon Tool";
|
|
4
|
-
|
|
5
|
-
global.CONFIG = {
|
|
6
|
-
github: githubURL,
|
|
7
|
-
notFoundMessage: `If you believe this is an error or is a new technology, please create an issue on ${githubURL} and we'll figure it out for you`,
|
|
8
|
-
version: version,
|
|
9
|
-
toolDesc: toolDesc
|
|
10
|
-
};
|
|
11
|
-
|
|
12
|
-
export default CONFIG;
|
package/index.js
DELETED
|
@@ -1,69 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
import { program } from "commander";
|
|
3
|
-
import lazyLoad from "./lazyLoad/index.js";
|
|
4
|
-
import endpoints from "./endpoints/index.js";
|
|
5
|
-
import CONFIG from "./globalConfig.js";
|
|
6
|
-
import strings from "./strings/index.js";
|
|
7
|
-
import apiGateway from "./api_gateway/index.js";
|
|
8
|
-
import * as globals from "./utility/globals.js";
|
|
9
|
-
|
|
10
|
-
program.version(CONFIG.version).description(CONFIG.toolDesc);
|
|
11
|
-
|
|
12
|
-
program
|
|
13
|
-
.command("lazyload")
|
|
14
|
-
.description("Run lazy load module")
|
|
15
|
-
.requiredOption("-u, --url <url/file>", "Target URL or a file containing a list of URLs (one per line)")
|
|
16
|
-
.option("-o, --output <directory>", "Output directory", "output")
|
|
17
|
-
.option("--strict-scope", "Download JS files from only the input URL domain", false)
|
|
18
|
-
.option("-s, --scope <scope>", "Download JS files from specific domains (comma-separated)", "*")
|
|
19
|
-
.option("-t, --threads <threads>", "Number of threads to use", 1)
|
|
20
|
-
.option("--subsequent-requests", "Download JS files from subsequent requests", false)
|
|
21
|
-
.option("--urls-file <file>", "Input JSON file containing URLs", "extracted_urls.json")
|
|
22
|
-
.option("--api-gateway", "Generate requests using API Gateway", false)
|
|
23
|
-
.option("--api-gateway-config <file>", "API Gateway config file", ".api_gateway_config.json")
|
|
24
|
-
.action(async (cmd) => {
|
|
25
|
-
globals.setApiGatewayConfigFile(cmd.apiGatewayConfig);
|
|
26
|
-
globals.setUseApiGateway(cmd.apiGateway);
|
|
27
|
-
await lazyLoad(cmd.url, cmd.output, cmd.strictScope, cmd.scope.split(","), cmd.threads, cmd.subsequentRequests, cmd.urlsFile);
|
|
28
|
-
});
|
|
29
|
-
|
|
30
|
-
program
|
|
31
|
-
.command("endpoints")
|
|
32
|
-
.description("Extract API endpoints")
|
|
33
|
-
.requiredOption("-u, --url <url>", "Target URL")
|
|
34
|
-
.option("-o, --output <file>", "Output file")
|
|
35
|
-
.action((cmd) => {
|
|
36
|
-
endpoints(cmd.url, cmd.output);
|
|
37
|
-
});
|
|
38
|
-
|
|
39
|
-
program
|
|
40
|
-
.command("strings")
|
|
41
|
-
.description("Extract strings from JS files")
|
|
42
|
-
.requiredOption("-d, --directory <directory>", "Directory containing JS files")
|
|
43
|
-
.option("-o, --output <file>", "JSON file to save the strings", "strings.json")
|
|
44
|
-
.option("-e, --extract-urls", "Extract URLs from strings", false)
|
|
45
|
-
.option("--extracted-url-path <file>", "Output JSON file for extracted URLs and paths", "extracted_urls.json")
|
|
46
|
-
.action((cmd) => {
|
|
47
|
-
strings(cmd.directory, cmd.output, cmd.extractUrls, cmd.extractedUrlPath);
|
|
48
|
-
});
|
|
49
|
-
|
|
50
|
-
program
|
|
51
|
-
.command("api-gateway")
|
|
52
|
-
.description("Configure AWS API Gateway to rotate IP addresses")
|
|
53
|
-
.option("-i, --init", "Initialize the config file (create API)", false)
|
|
54
|
-
.option("-d, --destroy <id>", "Destroy API with the given ID")
|
|
55
|
-
.option("--destroy-all", "Destroy all the API created by this tool in all regions", false)
|
|
56
|
-
.option("-r, --region <region>", "AWS region (default: random region)")
|
|
57
|
-
.option("-a, --access-key <access-key>", "AWS access key (if not provided, AWS_ACCESS_KEY_ID environment variable will be used)")
|
|
58
|
-
.option("-s, --secret-key <secret-key>", "AWS secret key (if not provided, AWS_SECRET_ACCESS_KEY environment variable will be used)")
|
|
59
|
-
.option("-c, --config <config>", "Name of the config file", ".api_gateway_config.json")
|
|
60
|
-
.option("-l, --list", "List all the API created by this tool", false)
|
|
61
|
-
.option("--feasibility", "Check feasibility of API Gateway", false)
|
|
62
|
-
.option("--feasibility-url <url>", "URL to check feasibility of")
|
|
63
|
-
.action((cmd) => {
|
|
64
|
-
globals.setApiGatewayConfigFile(cmd.config);
|
|
65
|
-
globals.setUseApiGateway(true);
|
|
66
|
-
apiGateway(cmd.init, cmd.destroy, cmd.destroyAll, cmd.list, cmd.region, cmd.accessKey, cmd.secretKey, cmd.config, cmd.feasibility, cmd.feasibilityUrl);
|
|
67
|
-
});
|
|
68
|
-
|
|
69
|
-
program.parse(process.argv);
|
|
@@ -1,122 +0,0 @@
|
|
|
1
|
-
import chalk from "chalk";
|
|
2
|
-
import path from "path";
|
|
3
|
-
import fs from "fs";
|
|
4
|
-
import prettier from "prettier";
|
|
5
|
-
import makeRequest from "../utility/makeReq.js";
|
|
6
|
-
import { getURLDirectory } from "../utility/urlUtils.js";
|
|
7
|
-
import { getScope, getMaxReqQueue } from "./globals.js"; // Import scope and max_req_queue functions
|
|
8
|
-
|
|
9
|
-
/**
|
|
10
|
-
* Downloads a list of URLs and saves them as files in the specified output directory.
|
|
11
|
-
* It creates the necessary subdirectories based on the URL's host and path.
|
|
12
|
-
* If the URL does not end with `.js`, it is skipped.
|
|
13
|
-
* The function logs the progress and any errors to the console.
|
|
14
|
-
* @param {string[]} urls - An array of URLs to be downloaded.
|
|
15
|
-
* @param {string} output - The directory where the downloaded files will be saved.
|
|
16
|
-
* @returns {Promise<void>}
|
|
17
|
-
*/
|
|
18
|
-
const downloadFiles = async (urls, output) => {
|
|
19
|
-
console.log(
|
|
20
|
-
chalk.cyan(`[i] Attempting to download ${urls.length} JS chunks`),
|
|
21
|
-
);
|
|
22
|
-
fs.mkdirSync(output, { recursive: true });
|
|
23
|
-
|
|
24
|
-
// to store ignored JS domain
|
|
25
|
-
let ignoredJSFiles = [];
|
|
26
|
-
let ignoredJSDomains = [];
|
|
27
|
-
|
|
28
|
-
let download_count = 0;
|
|
29
|
-
let queue = 0;
|
|
30
|
-
|
|
31
|
-
const downloadPromises = urls.map(async (url) => {
|
|
32
|
-
try {
|
|
33
|
-
if (url.match(/\.js/)) {
|
|
34
|
-
// get the directory of the url
|
|
35
|
-
const { host, directory } = getURLDirectory(url);
|
|
36
|
-
|
|
37
|
-
// check scope of file. Only if in scope, download it
|
|
38
|
-
if (!getScope().includes("*")) {
|
|
39
|
-
if (!getScope().includes(host)) {
|
|
40
|
-
ignoredJSFiles.push(url);
|
|
41
|
-
if (!ignoredJSDomains.includes(host)) {
|
|
42
|
-
ignoredJSDomains.push(host);
|
|
43
|
-
}
|
|
44
|
-
return;
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
// make the directory inside the output folder
|
|
49
|
-
const childDir = path.join(output, host, directory);
|
|
50
|
-
fs.mkdirSync(childDir, { recursive: true });
|
|
51
|
-
|
|
52
|
-
// check if queue is full. If so, then wait for random time between
|
|
53
|
-
// 50 to 300 ms. Then, check again, and loop the process
|
|
54
|
-
while (queue >= getMaxReqQueue()) {
|
|
55
|
-
await new Promise((resolve) =>
|
|
56
|
-
setTimeout(resolve, Math.random() * 250 + 50),
|
|
57
|
-
);
|
|
58
|
-
}
|
|
59
|
-
queue++;
|
|
60
|
-
const res = await makeRequest(url);
|
|
61
|
-
queue--;
|
|
62
|
-
|
|
63
|
-
const file = `// JS Source: ${url}\n${await res.text()}`;
|
|
64
|
-
let filename;
|
|
65
|
-
try {
|
|
66
|
-
filename = url
|
|
67
|
-
.split("/")
|
|
68
|
-
.pop()
|
|
69
|
-
.match(/[a-zA-Z0-9\.\-_]+\.js/)[0];
|
|
70
|
-
} catch (err) {
|
|
71
|
-
// split the URL into multiple chunks. then iterate
|
|
72
|
-
// through it, and find whatever matches with JS ext
|
|
73
|
-
const chunks = url.split("/");
|
|
74
|
-
for (const chunk of chunks) {
|
|
75
|
-
if (chunk.match(/\.js$/)) {
|
|
76
|
-
filename = chunk;
|
|
77
|
-
break;
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
if (!filename) { // Handle cases where filename might not be found
|
|
83
|
-
console.warn(chalk.yellow(`[!] Could not determine filename for URL: ${url}. Skipping.`));
|
|
84
|
-
return;
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
const filePath = path.join(childDir, filename);
|
|
88
|
-
try {
|
|
89
|
-
fs.writeFileSync(
|
|
90
|
-
filePath,
|
|
91
|
-
await prettier.format(file, { parser: "babel" }),
|
|
92
|
-
);
|
|
93
|
-
} catch (err) {
|
|
94
|
-
console.error(chalk.red(`[!] Failed to write file: ${filePath}`));
|
|
95
|
-
}
|
|
96
|
-
download_count++;
|
|
97
|
-
}
|
|
98
|
-
} catch (err) {
|
|
99
|
-
console.error(chalk.red(`[!] Failed to download: ${url}`));
|
|
100
|
-
}
|
|
101
|
-
});
|
|
102
|
-
|
|
103
|
-
await Promise.all(downloadPromises);
|
|
104
|
-
|
|
105
|
-
if (ignoredJSFiles.length > 0) {
|
|
106
|
-
console.log(
|
|
107
|
-
chalk.yellow(
|
|
108
|
-
`[i] Ignored ${ignoredJSFiles.length} JS files across ${ignoredJSDomains.length} domain(s) - ${ignoredJSDomains.join(", ")}`,
|
|
109
|
-
),
|
|
110
|
-
);
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
if (download_count > 0) {
|
|
114
|
-
console.log(
|
|
115
|
-
chalk.green(
|
|
116
|
-
`[✓] Downloaded ${download_count} JS chunks to ${output} directory`,
|
|
117
|
-
),
|
|
118
|
-
);
|
|
119
|
-
}
|
|
120
|
-
};
|
|
121
|
-
|
|
122
|
-
export default downloadFiles;
|
|
@@ -1,54 +0,0 @@
|
|
|
1
|
-
import chalk from "chalk";
|
|
2
|
-
import puppeteer from "puppeteer";
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
* Downloads all the lazy loaded JS files from a given URL.
|
|
6
|
-
*
|
|
7
|
-
* It opens a headless browser instance, navigates to the given URL, and
|
|
8
|
-
* intercepts all the requests. It checks if the request is a JS file
|
|
9
|
-
* and if it is a GET request. If both conditions are satisfied, the URL
|
|
10
|
-
* is added to the array of URLs. Finally, it closes the browser instance
|
|
11
|
-
* and returns the array of URLs.
|
|
12
|
-
*
|
|
13
|
-
* @param {string} url - The URL of the webpage to fetch and parse.
|
|
14
|
-
* @returns {Promise<string[]|undefined>} - A promise that resolves to an array of
|
|
15
|
-
* absolute URLs pointing to JavaScript files found in the page, or undefined for invalid URL.
|
|
16
|
-
*/
|
|
17
|
-
const downloadLoadedJs = async (url) => {
|
|
18
|
-
if (!url.match(/https?:\/\/[a-zA-Z0-9\._\-]+/)) {
|
|
19
|
-
console.log(chalk.red("[!] Invalid URL"));
|
|
20
|
-
return; // Return undefined as per JSDoc
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
const browser = await puppeteer.launch({
|
|
24
|
-
headless: true,
|
|
25
|
-
});
|
|
26
|
-
|
|
27
|
-
const page = await browser.newPage();
|
|
28
|
-
|
|
29
|
-
await page.setRequestInterception(true);
|
|
30
|
-
|
|
31
|
-
let js_urls_local = []; // Use a local variable, not the global one
|
|
32
|
-
page.on("request", async (request) => {
|
|
33
|
-
// get the request url
|
|
34
|
-
const req_url = request.url(); // Renamed to avoid conflict with outer 'url'
|
|
35
|
-
|
|
36
|
-
// see if the request is a JS file, and is a get request
|
|
37
|
-
if (
|
|
38
|
-
request.method() === "GET" &&
|
|
39
|
-
req_url.match(/https?:\/\/[a-z\._\-]+\/.+\.js\??.*/)
|
|
40
|
-
) {
|
|
41
|
-
js_urls_local.push(req_url);
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
await request.continue();
|
|
45
|
-
});
|
|
46
|
-
|
|
47
|
-
await page.goto(url);
|
|
48
|
-
|
|
49
|
-
await browser.close();
|
|
50
|
-
|
|
51
|
-
return js_urls_local;
|
|
52
|
-
};
|
|
53
|
-
|
|
54
|
-
export default downloadLoadedJs;
|
package/lazyLoad/globals.js
DELETED
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
|
|
2
|
-
let scope = [];
|
|
3
|
-
let js_urls = [];
|
|
4
|
-
let max_req_queue;
|
|
5
|
-
|
|
6
|
-
export const getScope = () => scope;
|
|
7
|
-
export const setScope = (newScope) => { scope = newScope; };
|
|
8
|
-
export const pushToScope = (item) => { scope.push(item); };
|
|
9
|
-
|
|
10
|
-
export const getJsUrls = () => js_urls;
|
|
11
|
-
export const clearJsUrls = () => { js_urls = []; };
|
|
12
|
-
export const pushToJsUrls = (url) => { js_urls.push(url); };
|
|
13
|
-
|
|
14
|
-
export const getMaxReqQueue = () => max_req_queue;
|
|
15
|
-
export const setMaxReqQueue = (newMax) => { max_req_queue = newMax; };
|
package/lazyLoad/index.js
DELETED
|
@@ -1,167 +0,0 @@
|
|
|
1
|
-
import chalk from "chalk";
|
|
2
|
-
import fs from "fs";
|
|
3
|
-
import frameworkDetect from "../techDetect/index.js";
|
|
4
|
-
import CONFIG from "../globalConfig.js";
|
|
5
|
-
import _traverse from "@babel/traverse";
|
|
6
|
-
const traverse = _traverse.default;
|
|
7
|
-
import { URL } from "url";
|
|
8
|
-
|
|
9
|
-
// Next.js
|
|
10
|
-
import subsequentRequests from "./next_js/next_SubsequentRequests.js";
|
|
11
|
-
import next_getJSScript from "./next_js/next_GetJSScript.js";
|
|
12
|
-
import next_getLazyResources from "./next_js/next_GetLazyResources.js";
|
|
13
|
-
|
|
14
|
-
// Nuxt.js
|
|
15
|
-
import nuxt_getFromPageSource from "./nuxt_js/nuxt_getFromPageSource.js";
|
|
16
|
-
import nuxt_stringAnalysisJSFiles from "./nuxt_js/nuxt_stringAnalysisJSFiles.js";
|
|
17
|
-
import nuxt_astParse from "./nuxt_js/nuxt_astParse.js";
|
|
18
|
-
|
|
19
|
-
// generic
|
|
20
|
-
import downloadFiles from "./downloadFilesUtil.js";
|
|
21
|
-
import downloadLoadedJs from "./downloadLoadedJsUtil.js";
|
|
22
|
-
|
|
23
|
-
// import global vars
|
|
24
|
-
import * as globals from "./globals.js";
|
|
25
|
-
|
|
26
|
-
/**
|
|
27
|
-
* Downloads all lazy-loaded JavaScript files from the specified URL or file containing URLs.
|
|
28
|
-
*
|
|
29
|
-
* The function detects the JavaScript framework used by the webpage (e.g., Next.js, Nuxt.js)
|
|
30
|
-
* and utilizes specific techniques to find and download lazy-loaded JS files.
|
|
31
|
-
* It supports subsequent requests for additional JS files if specified.
|
|
32
|
-
*
|
|
33
|
-
* @param {string} url - The URL or path to a file containing a list of URLs to process.
|
|
34
|
-
* @param {string} output - The directory where downloaded files will be saved.
|
|
35
|
-
* @param {boolean} strictScope - Whether to restrict downloads to the input URL domain.
|
|
36
|
-
* @param {string[]} inputScope - Specific domains to download JS files from.
|
|
37
|
-
* @param {number} threads - The number of threads to use for downloading files.
|
|
38
|
-
* @param {boolean} subsequentRequestsFlag - Whether to include JS files from subsequent requests.
|
|
39
|
-
* @param {string} urlsFile - The JSON file containing additional URLs for subsequent requests.
|
|
40
|
-
* @returns {Promise<void>}
|
|
41
|
-
*/
|
|
42
|
-
const lazyLoad = async (
|
|
43
|
-
url,
|
|
44
|
-
output,
|
|
45
|
-
strictScope,
|
|
46
|
-
inputScope,
|
|
47
|
-
threads,
|
|
48
|
-
subsequentRequestsFlag,
|
|
49
|
-
urlsFile,
|
|
50
|
-
) => {
|
|
51
|
-
console.log(chalk.cyan("[i] Loading 'Lazy Load' module"));
|
|
52
|
-
|
|
53
|
-
let urls;
|
|
54
|
-
|
|
55
|
-
// check if the url is file or a URL
|
|
56
|
-
if (fs.existsSync(url)) {
|
|
57
|
-
urls = fs.readFileSync(url, "utf-8").split("\n");
|
|
58
|
-
// remove the empty lines
|
|
59
|
-
urls = urls.filter((url) => url.trim() !== "");
|
|
60
|
-
} else if (url.match(/https?:\/\/[a-zA-Z0-9\-_\.:]+/)) {
|
|
61
|
-
urls = [url];
|
|
62
|
-
} else {
|
|
63
|
-
console.log(chalk.red("[!] Invalid URL or file path"));
|
|
64
|
-
return;
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
for (const url of urls) {
|
|
68
|
-
console.log(chalk.cyan(`[i] Processing ${url}`));
|
|
69
|
-
|
|
70
|
-
if (strictScope) {
|
|
71
|
-
globals.pushToScope(new URL(url).host);
|
|
72
|
-
} else {
|
|
73
|
-
globals.setScope(inputScope);
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
globals.setMaxReqQueue(threads);
|
|
77
|
-
globals.clearJsUrls(); // Initialize js_urls for each URL processing in the loop
|
|
78
|
-
|
|
79
|
-
const tech = await frameworkDetect(url);
|
|
80
|
-
|
|
81
|
-
if (tech) {
|
|
82
|
-
if (tech.name === "next") {
|
|
83
|
-
console.log(chalk.green("[✓] Next.js detected"));
|
|
84
|
-
console.log(chalk.yellow(`Evidence: ${tech.evidence}`));
|
|
85
|
-
|
|
86
|
-
// find the JS files from script of the webpage
|
|
87
|
-
const jsFilesFromScriptTag = await next_getJSScript(url);
|
|
88
|
-
|
|
89
|
-
// get lazy resources
|
|
90
|
-
const lazyResourcesFromWebpack = await next_getLazyResources(url);
|
|
91
|
-
let lazyResourcesFromSubsequentRequests;
|
|
92
|
-
|
|
93
|
-
if (subsequentRequestsFlag) {
|
|
94
|
-
// get JS files from subsequent requests
|
|
95
|
-
lazyResourcesFromSubsequentRequests = await subsequentRequests(
|
|
96
|
-
url,
|
|
97
|
-
urlsFile,
|
|
98
|
-
threads,
|
|
99
|
-
output,
|
|
100
|
-
globals.getJsUrls(), // Pass the global js_urls
|
|
101
|
-
);
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
// download the resources
|
|
105
|
-
// but combine them first
|
|
106
|
-
let jsFilesToDownload = [
|
|
107
|
-
...(jsFilesFromScriptTag || []),
|
|
108
|
-
...(lazyResourcesFromWebpack || []),
|
|
109
|
-
...(lazyResourcesFromSubsequentRequests || []),
|
|
110
|
-
];
|
|
111
|
-
// Ensure js_urls from globals are included if next_getJSScript or next_getLazyResources populated it.
|
|
112
|
-
// This is because those functions now push to the global js_urls via setters.
|
|
113
|
-
// The return values of next_getJSScript and next_getLazyResources might be the same array instance
|
|
114
|
-
// or a new one depending on their implementation, so explicitly get the global one here.
|
|
115
|
-
jsFilesToDownload.push(...globals.getJsUrls());
|
|
116
|
-
|
|
117
|
-
// dedupe the files
|
|
118
|
-
jsFilesToDownload = [...new Set(jsFilesToDownload)];
|
|
119
|
-
|
|
120
|
-
await downloadFiles(jsFilesToDownload, output);
|
|
121
|
-
} else if (tech.name === "vue") {
|
|
122
|
-
console.log(chalk.green("[✓] Vue.js detected"));
|
|
123
|
-
console.log(chalk.yellow(`Evidence: ${tech.evidence}`));
|
|
124
|
-
} else if (tech.name === "nuxt") {
|
|
125
|
-
console.log(chalk.green("[✓] Nuxt.js detected"));
|
|
126
|
-
console.log(chalk.yellow(`Evidence: ${tech.evidence}`));
|
|
127
|
-
|
|
128
|
-
let jsFilesToDownload = [];
|
|
129
|
-
|
|
130
|
-
// find the files from the page source
|
|
131
|
-
const jsFilesFromPageSource = await nuxt_getFromPageSource(url);
|
|
132
|
-
const jsFilesFromStringAnalysis = await nuxt_stringAnalysisJSFiles(url);
|
|
133
|
-
|
|
134
|
-
jsFilesToDownload.push(...jsFilesFromPageSource);
|
|
135
|
-
jsFilesToDownload.push(...jsFilesFromStringAnalysis);
|
|
136
|
-
// dedupe the files
|
|
137
|
-
jsFilesToDownload = [...new Set(jsFilesToDownload)];
|
|
138
|
-
|
|
139
|
-
let jsFilesFromAST = [];
|
|
140
|
-
console.log(chalk.cyan("[i] Analyzing functions in the files found"));
|
|
141
|
-
for (const jsFile of jsFilesToDownload) {
|
|
142
|
-
jsFilesFromAST.push(...(await nuxt_astParse(jsFile)));
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
jsFilesToDownload.push(...jsFilesFromAST);
|
|
146
|
-
|
|
147
|
-
jsFilesToDownload.push(...globals.getJsUrls());
|
|
148
|
-
|
|
149
|
-
// dedupe the files
|
|
150
|
-
jsFilesToDownload = [...new Set(jsFilesToDownload)];
|
|
151
|
-
|
|
152
|
-
await downloadFiles(jsFilesToDownload, output);
|
|
153
|
-
}
|
|
154
|
-
} else {
|
|
155
|
-
console.log(chalk.red("[!] Framework not detected :("));
|
|
156
|
-
console.log(chalk.magenta(CONFIG.notFoundMessage));
|
|
157
|
-
console.log(chalk.yellow("[i] Trying to download loaded JS files"));
|
|
158
|
-
const js_urls = await downloadLoadedJs(url);
|
|
159
|
-
if (js_urls && js_urls.length > 0) {
|
|
160
|
-
console.log(chalk.green(`[✓] Found ${js_urls.length} JS chunks`));
|
|
161
|
-
await downloadFiles(js_urls, output);
|
|
162
|
-
}
|
|
163
|
-
}
|
|
164
|
-
}
|
|
165
|
-
};
|
|
166
|
-
|
|
167
|
-
export default lazyLoad;
|
|
@@ -1,99 +0,0 @@
|
|
|
1
|
-
// lazyLoad/nextGetJSScript.js
|
|
2
|
-
import chalk from "chalk";
|
|
3
|
-
import { URL } from "url";
|
|
4
|
-
import * as cheerio from "cheerio";
|
|
5
|
-
import makeRequest from "../../utility/makeReq.js";
|
|
6
|
-
import { getJsUrls, pushToJsUrls } from "../globals.js";
|
|
7
|
-
|
|
8
|
-
/**
|
|
9
|
-
* Asynchronously fetches the given URL and extracts JavaScript file URLs
|
|
10
|
-
* from script tags present in the HTML content.
|
|
11
|
-
*
|
|
12
|
-
* @param {string} url - The URL of the webpage to fetch and parse.
|
|
13
|
-
* @returns {Promise<string[]>} - A promise that resolves to an array of
|
|
14
|
-
* absolute URLs pointing to JavaScript files found in script tags.
|
|
15
|
-
*/
|
|
16
|
-
const next_getJSScript = async (url) => {
|
|
17
|
-
// get the page source
|
|
18
|
-
const res = await makeRequest(url);
|
|
19
|
-
const pageSource = await res.text();
|
|
20
|
-
|
|
21
|
-
// cheerio to parse the page source
|
|
22
|
-
const $ = cheerio.load(pageSource);
|
|
23
|
-
|
|
24
|
-
// find all script tags
|
|
25
|
-
const scriptTags = $("script");
|
|
26
|
-
|
|
27
|
-
// iterate through script tags
|
|
28
|
-
for (const scriptTag of scriptTags) {
|
|
29
|
-
// get the src attribute
|
|
30
|
-
const src = $(scriptTag).attr("src");
|
|
31
|
-
|
|
32
|
-
// see if the src is a JS file
|
|
33
|
-
if (
|
|
34
|
-
src !== undefined &&
|
|
35
|
-
src.match(/(https:\/\/[a-zA-Z0-9_\_\.]+\/.+\.js\??.*|\/.+\.js\??.*)/)) {
|
|
36
|
-
// if the src starts with /, like `/static/js/a.js` find the absolute URL
|
|
37
|
-
if (src.startsWith("/")) {
|
|
38
|
-
const absoluteUrl = new URL(url).origin + src;
|
|
39
|
-
if (!getJsUrls().includes(absoluteUrl)) {
|
|
40
|
-
pushToJsUrls(absoluteUrl);
|
|
41
|
-
}
|
|
42
|
-
} else if (src.match(/^[^/]/)) {
|
|
43
|
-
// if the src is a relative URL, like `static/js/a.js` find the absolute URL
|
|
44
|
-
// Get directory URL (origin + path without filename)
|
|
45
|
-
const pathParts = new URL(url).pathname.split("/");
|
|
46
|
-
pathParts.pop(); // remove filename from last
|
|
47
|
-
const directory = new URL(url).origin + pathParts.join("/") + "/";
|
|
48
|
-
|
|
49
|
-
if (!getJsUrls().includes(directory + src)) {
|
|
50
|
-
pushToJsUrls(directory + src);
|
|
51
|
-
}
|
|
52
|
-
} else {
|
|
53
|
-
if (!getJsUrls().includes(src)) {
|
|
54
|
-
pushToJsUrls(src);
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
} else {
|
|
58
|
-
// if the script tag is inline, it could contain static JS URL
|
|
59
|
-
// to get these, simply regex from the JS script
|
|
60
|
-
|
|
61
|
-
const js_script = $(scriptTag).html();
|
|
62
|
-
const matches = js_script.match(/static\/chunks\/[a-zA-Z0-9_\-]+\.js/g);
|
|
63
|
-
|
|
64
|
-
if (matches) {
|
|
65
|
-
const uniqueMatches = [...new Set(matches)];
|
|
66
|
-
for (const match of uniqueMatches) {
|
|
67
|
-
// if it is using that static/chunks/ pattern, I can just get the filename
|
|
68
|
-
const filename = match.replace("static/chunks/", "");
|
|
69
|
-
|
|
70
|
-
// go through the already found URLs, coz they will have it (src attribute
|
|
71
|
-
// is there before inline things)
|
|
72
|
-
|
|
73
|
-
let js_path_dir;
|
|
74
|
-
|
|
75
|
-
for (const js_url of getJsUrls()) {
|
|
76
|
-
if (
|
|
77
|
-
!js_path_dir &&
|
|
78
|
-
new URL(js_url).host === new URL(url).host &&
|
|
79
|
-
new URL(js_url).pathname.includes("static/chunks/")
|
|
80
|
-
) {
|
|
81
|
-
js_path_dir = js_url.replace(/\/[^\/]+\.js.*$/, "");
|
|
82
|
-
}
|
|
83
|
-
}
|
|
84
|
-
if (js_path_dir) { // Ensure js_path_dir was found
|
|
85
|
-
pushToJsUrls(js_path_dir + "/" + filename);
|
|
86
|
-
}
|
|
87
|
-
}
|
|
88
|
-
}
|
|
89
|
-
}
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
console.log(
|
|
93
|
-
chalk.green(`[✓] Found ${getJsUrls().length} JS files from the script tags`),
|
|
94
|
-
);
|
|
95
|
-
|
|
96
|
-
return getJsUrls();
|
|
97
|
-
};
|
|
98
|
-
|
|
99
|
-
export default next_getJSScript;
|