Skip to content

Commit 8292bae

Browse files
authored
Merge pull request #45 from shriyanss/dev
v1.2.1-alpha.2 ## 1.2.1-alpha.2 - 2025.08.06 ### Added - Added support for parsing URL list in the run module ### Changed ### Fixed
2 parents a822a08 + ed454e7 commit 8292bae

File tree

6 files changed

+135
-63
lines changed

6 files changed

+135
-63
lines changed

.gitignore

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -152,4 +152,6 @@ mapped-openapi.json
152152
test.yaml
153153
analyze.json
154154
js-recon.db
155-
report.html
155+
report.html
156+
js_recon_run_output/
157+
urls.txt

CHANGELOG.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,15 @@
11
# Change Log
22

3+
## 1.2.1-alpha.2 - 2025.08.06
4+
5+
### Added
6+
7+
- Added support for parsing URL list in the run module
8+
9+
### Changed
10+
11+
### Fixed
12+
313
## 1.2.1-alpha.1 - 2025.08.04
414

515
### Added

package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@shriyanss/js-recon",
3-
"version": "1.2.1-alpha.1",
3+
"version": "1.2.1-alpha.2",
44
"description": "JS Recon Tool",
55
"main": "build/index.js",
66
"type": "module",
@@ -12,7 +12,7 @@
1212
"build": "rm -rf build/ && tsc",
1313
"start": "node build/index.js",
1414
"test": "node build/index.js -h",
15-
"cleanup": "rm -rf build output .resp_cache.json endpoints.json extracted_urls{.txt,.json,-openapi.json} strings.json mapped{-openapi.json,.json} analyze.json test{.yaml,.js} shriyanss-js-recon-*.tgz js-recon.db report.{html,md} && tsc"
15+
"cleanup": "rm -rf build output .resp_cache.json endpoints.json extracted_urls{.txt,.json,-openapi.json} strings.json mapped{-openapi.json,.json} analyze.json test{.yaml,.js} shriyanss-js-recon-*.tgz js-recon.db report.{html,md} js_recon_run_output && tsc"
1616
},
1717
"keywords": [],
1818
"author": "Shriyans Sudhi",

src/globalConfig.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
const githubURL = "https://github.com/shriyanss/js-recon";
22
const modulesDocs = "https://js-recon.io/docs/category/modules";
3-
const version = "1.2.1-alpha.1";
3+
const version = "1.2.1-alpha.2";
44
const toolDesc = "JS Recon Tool";
55
const axiosNonHttpMethods = ["isAxiosError"]; // methods available in axios, which are not for making HTTP requests
66

src/lazyLoad/globals.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,17 @@ export const pushToScope = (item) => {
1212
};
1313

1414
export const getJsUrls = () => js_urls;
15+
export const clearJsUrls = () => {
16+
js_urls = [];
17+
};
1518
export const pushToJsUrls = (url) => {
1619
js_urls.push(url);
1720
};
1821

1922
export const getJsonUrls = () => json_urls;
23+
export const clearJsonUrls = () => {
24+
json_urls = [];
25+
};
2026
export const pushToJsonUrls = (url: string) => json_urls.push(url);
2127

2228
export const getMaxReqQueue = () => max_req_queue;

src/run/index.ts

Lines changed: 113 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -8,57 +8,27 @@ import chalk from "chalk";
88
import CONFIG from "../globalConfig.js";
99
import analyze from "../analyze/index.js";
1010
import report from "../report/index.js";
11+
import { clearJsUrls, clearJsonUrls } from "../lazyLoad/globals.js";
1112

12-
export default async (cmd) => {
13-
globalsUtil.setApiGatewayConfigFile(cmd.apiGatewayConfig);
14-
globalsUtil.setUseApiGateway(cmd.apiGateway);
15-
globalsUtil.setDisableCache(cmd.disableCache);
16-
globalsUtil.setRespCacheFile(cmd.cacheFile);
17-
globalsUtil.setYes(cmd.yes);
13+
const processUrl = async (url, outputDir, workingDir, cmd, isBatch) => {
14+
const targetHost = new URL(url).host.replace(":", "_");
1815

19-
// check if the given URL is a file
20-
if (fs.existsSync(cmd.url)) {
21-
console.log(chalk.red(`[!] Please provide a single URL. Parsing a list of URLs isn't available`));
22-
console.log(
23-
chalk.yellow(
24-
`To run the tool against, a list of targets, pass the file in '-u' flag of 'lazyload' module, and it will download the JS files`
25-
)
26-
);
27-
return;
28-
}
16+
console.log(chalk.bgGreenBright(`[+] Starting analysis for ${url}...`));
2917

30-
// check if output directory exists. If so, ask the user to switch to other directory
31-
// if not done, it might conflict this process
32-
// for devs: run `npm run cleanup` to prepare this directory
33-
if (fs.existsSync(cmd.output)) {
34-
console.log(
35-
chalk.red(
36-
`[!] Output directory ${cmd.output} already exists. Please switch to other directory or it might conflict with this process.`
37-
)
38-
);
39-
console.log(
40-
chalk.yellow(
41-
`[i] For advanced users: use the individual modules separately. See docs at ${CONFIG.modulesDocs}`
42-
)
43-
);
44-
return;
18+
if (isBatch) {
19+
clearJsUrls();
20+
clearJsonUrls();
4521
}
4622

47-
const targetHost = new URL(cmd.url).host.replace(":", "_");
48-
49-
console.log(chalk.bgGreenBright("[+] Starting analysis..."));
50-
5123
console.log(chalk.bgCyan("[1/8] Running lazyload to download JavaScript files..."));
52-
await lazyLoad(cmd.url, cmd.output, cmd.strictScope, cmd.scope.split(","), cmd.threads, false, "", cmd.insecure);
24+
await lazyLoad(url, outputDir, cmd.strictScope, cmd.scope.split(","), cmd.threads, false, "", cmd.insecure);
5325
console.log(chalk.bgGreen("[+] Lazyload complete."));
5426

55-
// if tech is undefined, i.e. it can't be detected, quit. Nothing to be done :(
5627
if (globalsUtil.getTech() === "") {
5728
console.log(chalk.bgRed("[!] Technology not detected. Quitting."));
5829
return;
5930
}
6031

61-
// since the app only supports next.js now, move ahead only if the tech is next
6232
if (globalsUtil.getTech() !== "next") {
6333
console.log(
6434
chalk.bgYellow(
@@ -68,57 +38,141 @@ export default async (cmd) => {
6838
return;
6939
}
7040

71-
// run strings
41+
const stringsFile = isBatch ? `${workingDir}/strings.json` : "strings.json";
42+
const extractedUrlsFile = isBatch ? `${workingDir}/extracted_urls` : "extracted_urls";
43+
const mappedFile = isBatch ? `${workingDir}/mapped` : "mapped";
44+
const mappedJsonFile = isBatch ? `${workingDir}/mapped.json` : "mapped.json";
45+
const endpointsFile = isBatch ? `${workingDir}/endpoints` : "endpoints";
46+
const openapiFile = isBatch ? `${workingDir}/mapped-openapi.json` : "mapped-openapi.json";
47+
const analyzeFile = isBatch ? `${workingDir}/analyze.json` : "analyze.json";
48+
const reportDbFile = isBatch ? `${workingDir}/js-recon.db` : "js-recon.db";
49+
const reportFile = isBatch ? `${workingDir}/report` : "report";
50+
7251
console.log(chalk.bgCyan("[2/8] Running strings to extract endpoints..."));
73-
await strings(cmd.output, "strings.json", true, "extracted_urls", false, false, false);
52+
await strings(outputDir, stringsFile, true, extractedUrlsFile, false, false, false);
7453
console.log(chalk.bgGreen("[+] Strings complete."));
7554

76-
// run lazyload with subsequent requests
7755
console.log(chalk.bgCyan("[3/8] Running lazyload with subsequent requests to download JavaScript files..."));
7856
await lazyLoad(
79-
cmd.url,
80-
cmd.output,
57+
url,
58+
outputDir,
8159
cmd.strictScope,
8260
cmd.scope.split(","),
8361
cmd.threads,
8462
true,
85-
"extracted_urls.json",
63+
`${extractedUrlsFile}.json`,
8664
cmd.insecure
8765
);
8866
console.log(chalk.bgGreen("[+] Lazyload with subsequent requests complete."));
8967

90-
// run strings again to extract endpoints from the files that are downloaded in the previous step
9168
console.log(chalk.bgCyan("[4/8] Running strings again to extract endpoints..."));
92-
await strings(cmd.output, "strings.json", true, "extracted_urls", cmd.secrets, true, true);
69+
await strings(outputDir, stringsFile, true, extractedUrlsFile, cmd.secrets, true, true);
9370
console.log(chalk.bgGreen("[+] Strings complete."));
9471

95-
// now, run map
9672
console.log(chalk.bgCyan("[5/8] Running map to find functions..."));
9773
globalsUtil.setOpenapi(true);
98-
await map(cmd.output + "/" + targetHost, "mapped", ["json"], globalsUtil.getTech(), false, false);
74+
if (isBatch) {
75+
globalsUtil.setOpenapiOutputFile(openapiFile);
76+
}
77+
await map(outputDir + "/" + targetHost, mappedFile, ["json"], globalsUtil.getTech(), false, false);
9978
console.log(chalk.bgGreen("[+] Map complete."));
10079

101-
// now, run endpoints
10280
console.log(chalk.bgCyan("[6/8] Running endpoints to extract endpoints..."));
103-
// check if the subsequent requests directory exists
104-
if (fs.existsSync(`${cmd.output}/${targetHost}/___subsequent_requests`)) {
105-
await endpoints(cmd.url, `${cmd.output}/${targetHost}/`, "endpoints", ["json"], "next", false, "mapped.json");
81+
if (fs.existsSync(`${outputDir}/${targetHost}/___subsequent_requests`)) {
82+
await endpoints(url, `${outputDir}/${targetHost}/`, endpointsFile, ["json"], "next", false, mappedJsonFile);
10683
} else {
107-
await endpoints(cmd.url, undefined, "endpoints", ["json"], "next", false, "mapped.json");
84+
await endpoints(url, undefined, endpointsFile, ["json"], "next", false, mappedJsonFile);
10885
}
10986
console.log(chalk.bgGreen("[+] Endpoints complete."));
11087

111-
// run the analyze module now
11288
console.log(chalk.bgCyan("[7/8] Running analyze to extract endpoints..."));
113-
// since the thirs argument is tech, and it can't be "all", so adding type ignore
11489
// @ts-ignore
115-
await analyze("", "mapped.json", globalsUtil.getTech(), false, "mapped-openapi.json", false, "analyze.json");
90+
await analyze("", mappedJsonFile, globalsUtil.getTech(), false, openapiFile, false, analyzeFile);
11691
console.log(chalk.bgGreen("[+] Analyze complete."));
11792

118-
// run the report module now
11993
console.log(chalk.bgCyan("[8/8] Running report module..."));
120-
await report("js-recon.db", "mapped.json", "analyze.json", "endpoints.json", "mapped-openapi.json", "report");
94+
await report(reportDbFile, mappedJsonFile, analyzeFile, `${endpointsFile}.json`, openapiFile, reportFile);
12195
console.log(chalk.bgGreen("[+] Report complete."));
12296

123-
console.log(chalk.bgGreenBright("[+] Analysis complete."));
97+
console.log(chalk.bgGreenBright(`[+] Analysis complete for ${url}.`));
98+
};
99+
100+
export default async (cmd) => {
101+
globalsUtil.setApiGatewayConfigFile(cmd.apiGatewayConfig);
102+
globalsUtil.setUseApiGateway(cmd.apiGateway);
103+
globalsUtil.setDisableCache(cmd.disableCache);
104+
globalsUtil.setRespCacheFile(cmd.cacheFile);
105+
globalsUtil.setYes(cmd.yes);
106+
107+
// check if the given URL is a file
108+
if (!fs.existsSync(cmd.url)) {
109+
// check if output directory exists. If so, ask the user to switch to other directory
110+
// if not done, it might conflict this process
111+
// for devs: run `npm run cleanup` to prepare this directory
112+
if (fs.existsSync(cmd.output)) {
113+
console.log(
114+
chalk.red(
115+
`[!] Output directory ${cmd.output} already exists. Please switch to other directory or it might conflict with this process.`
116+
)
117+
);
118+
console.log(
119+
chalk.yellow(
120+
`[i] For advanced users: use the individual modules separately. See docs at ${CONFIG.modulesDocs}`
121+
)
122+
);
123+
return;
124+
}
125+
126+
let urlTest = new URL(cmd.url);
127+
if (!urlTest) {
128+
console.log(chalk.red("[!] Invalid URL"));
129+
return;
130+
}
131+
132+
await processUrl(cmd.url, cmd.output, ".", cmd, false);
133+
} else {
134+
// since this is a file, we need to first load the URLs in the memory remove empty strings
135+
const urls = fs
136+
.readFileSync(cmd.url, "utf-8")
137+
.split("\n")
138+
.filter((url) => url !== "");
139+
140+
// iterate through the URLs, and make sure they are valid URLs
141+
let allPassed = true;
142+
for (const url of urls) {
143+
try {
144+
let urlTest = new URL(url);
145+
} catch (e) {
146+
console.log(chalk.red(`[!] Invalid URL: ${url}`));
147+
allPassed = false;
148+
}
149+
}
150+
if (!allPassed) {
151+
return;
152+
}
153+
154+
// first of all, make a new directory for the tool output
155+
const toolOutputDir = "js_recon_run_output";
156+
if (fs.existsSync(toolOutputDir)) {
157+
console.log(
158+
chalk.red(
159+
`[!] Output directory ${toolOutputDir} already exists. Please switch to other directory or it might conflict with this process.`
160+
)
161+
);
162+
console.log(
163+
chalk.yellow(
164+
`[i] For advanced users: use the individual modules separately. See docs at ${CONFIG.modulesDocs}`
165+
)
166+
);
167+
return;
168+
}
169+
fs.mkdirSync(toolOutputDir);
170+
171+
for (const url of urls) {
172+
const thisTargetWorkingDir = toolOutputDir + "/" + new URL(url).host.replace(":", "_");
173+
fs.mkdirSync(thisTargetWorkingDir);
174+
const outputDir = thisTargetWorkingDir + "/output";
175+
await processUrl(url, outputDir, thisTargetWorkingDir, cmd, true);
176+
}
177+
}
124178
};

0 commit comments

Comments
 (0)