@js-recon/js-recon 1.4.3 → 2.0.1-alpha.1

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.
Files changed (461) hide show
  1. package/.claude-sync/sync.sh +1 -1
  2. package/.github/workflows/build-and-prettify.yaml +55 -25
  3. package/.github/workflows/codeql.yml +33 -0
  4. package/.github/workflows/exploit-smoke-test.yaml +160 -0
  5. package/.github/workflows/framework-detection-smoke-test.yaml +135 -0
  6. package/.github/workflows/plumber.yml +20 -0
  7. package/.github/workflows/promote-js-recon.yml +5 -3
  8. package/.github/workflows/publish-js-recon.yml +6 -1
  9. package/.github/workflows/rules-smoke-test.yaml +15 -7
  10. package/.nvmrc +1 -0
  11. package/.plumber.yaml +151 -0
  12. package/CHANGELOG.md +54 -0
  13. package/CONTRIBUTING.md +32 -0
  14. package/Dockerfile +1 -0
  15. package/README.md +55 -2
  16. package/SECURITY.md +1 -1
  17. package/build/analyze/engine/astEngine.js +10 -9
  18. package/build/analyze/engine/astEngine.js.map +1 -1
  19. package/build/analyze/engine/csMastSEngine.js +6 -6
  20. package/build/analyze/engine/csMastSEngine.js.map +1 -1
  21. package/build/analyze/engine/index.js +1 -1
  22. package/build/analyze/engine/index.js.map +1 -1
  23. package/build/analyze/engine/requestEngine.js +6 -6
  24. package/build/analyze/engine/requestEngine.js.map +1 -1
  25. package/build/analyze/helpers/determineCompatibleVersion.js +70 -0
  26. package/build/analyze/helpers/determineCompatibleVersion.js.map +1 -0
  27. package/build/analyze/helpers/engineHelpers/findMemberExpressionAssignment.js +9 -3
  28. package/build/analyze/helpers/engineHelpers/findMemberExpressionAssignment.js.map +1 -1
  29. package/build/analyze/helpers/initRules.js +42 -24
  30. package/build/analyze/helpers/initRules.js.map +1 -1
  31. package/build/analyze/helpers/outputHelper.js +3 -3
  32. package/build/analyze/helpers/outputHelper.js.map +1 -1
  33. package/build/analyze/helpers/schemas.js +1 -0
  34. package/build/analyze/helpers/schemas.js.map +1 -1
  35. package/build/analyze/helpers/validate.js +9 -5
  36. package/build/analyze/helpers/validate.js.map +1 -1
  37. package/build/analyze/index.js +26 -16
  38. package/build/analyze/index.js.map +1 -1
  39. package/build/cliProgram.js +710 -0
  40. package/build/cliProgram.js.map +1 -0
  41. package/build/completion/index.js +245 -339
  42. package/build/completion/index.js.map +1 -1
  43. package/build/completion/introspect.js +17 -0
  44. package/build/completion/introspect.js.map +1 -0
  45. package/build/config/applicationConfig.js +494 -0
  46. package/build/config/applicationConfig.js.map +1 -0
  47. package/build/cs_mast/index.js +18 -17
  48. package/build/cs_mast/index.js.map +1 -1
  49. package/build/endpoints/gen_report/gen_json.js +2 -2
  50. package/build/endpoints/gen_report/gen_json.js.map +1 -1
  51. package/build/endpoints/gen_report/utility/iterate_n_store.js +1 -1
  52. package/build/endpoints/gen_report/utility/iterate_n_store.js.map +1 -1
  53. package/build/endpoints/index.js +12 -12
  54. package/build/endpoints/index.js.map +1 -1
  55. package/build/endpoints/next_js/client_jsFilesHref.js +3 -3
  56. package/build/endpoints/next_js/client_jsFilesHref.js.map +1 -1
  57. package/build/endpoints/next_js/client_jsonParse.js +4 -4
  58. package/build/endpoints/next_js/client_jsonParse.js.map +1 -1
  59. package/build/endpoints/next_js/client_mappedJsonFile.js +6 -6
  60. package/build/endpoints/next_js/client_mappedJsonFile.js.map +1 -1
  61. package/build/endpoints/next_js/client_subsequentRequests.js +5 -5
  62. package/build/endpoints/next_js/client_subsequentRequests.js.map +1 -1
  63. package/build/exploit/angular/cve-2026-68945.js +61 -0
  64. package/build/exploit/angular/cve-2026-68945.js.map +1 -0
  65. package/build/exploit/index.js +60 -0
  66. package/build/exploit/index.js.map +1 -0
  67. package/build/exploit/next/cve-2025-29927.js +65 -0
  68. package/build/exploit/next/cve-2025-29927.js.map +1 -0
  69. package/build/exploit/next/cve-2026-64645.js +51 -0
  70. package/build/exploit/next/cve-2026-64645.js.map +1 -0
  71. package/build/exploit/nuxt/cve-2026-71315.js +47 -0
  72. package/build/exploit/nuxt/cve-2026-71315.js.map +1 -0
  73. package/build/exploit/nuxt/cve-2026-71320.js +114 -0
  74. package/build/exploit/nuxt/cve-2026-71320.js.map +1 -0
  75. package/build/exploit/react/cve-2025-55182.js +116 -0
  76. package/build/exploit/react/cve-2025-55182.js.map +1 -0
  77. package/build/exploit/registry/cveRegistry.js +115 -0
  78. package/build/exploit/registry/cveRegistry.js.map +1 -0
  79. package/build/exploit/types.js +2 -0
  80. package/build/exploit/types.js.map +1 -0
  81. package/build/exploit/utility/compareResponses.js +29 -0
  82. package/build/exploit/utility/compareResponses.js.map +1 -0
  83. package/build/exploit/utility/outputHelper.js +22 -0
  84. package/build/exploit/utility/outputHelper.js.map +1 -0
  85. package/build/exploit/utility/rawRequest.js +54 -0
  86. package/build/exploit/utility/rawRequest.js.map +1 -0
  87. package/build/exploit/utility/sandboxRce.js +49 -0
  88. package/build/exploit/utility/sandboxRce.js.map +1 -0
  89. package/build/exploit/utility/toEngineOutput.js +28 -0
  90. package/build/exploit/utility/toEngineOutput.js.map +1 -0
  91. package/build/exploit/utility/wsClient.js +78 -0
  92. package/build/exploit/utility/wsClient.js.map +1 -0
  93. package/build/exploit/vite/cve-2025-30208.js +44 -0
  94. package/build/exploit/vite/cve-2025-30208.js.map +1 -0
  95. package/build/exploit/vite/cve-2026-39363.js +60 -0
  96. package/build/exploit/vite/cve-2026-39363.js.map +1 -0
  97. package/build/fingerprint/index.js +11 -21
  98. package/build/fingerprint/index.js.map +1 -1
  99. package/build/globalConfig.js +2 -2
  100. package/build/globalConfig.js.map +1 -1
  101. package/build/index.js +16 -555
  102. package/build/index.js.map +1 -1
  103. package/build/lazyLoad/angular/angular_getFromPageSource.js +3 -3
  104. package/build/lazyLoad/angular/angular_getFromPageSource.js.map +1 -1
  105. package/build/lazyLoad/downloadFilesUtil.js +51 -40
  106. package/build/lazyLoad/downloadFilesUtil.js.map +1 -1
  107. package/build/lazyLoad/downloadQueue.js +154 -50
  108. package/build/lazyLoad/downloadQueue.js.map +1 -1
  109. package/build/lazyLoad/downloadResponse.js +113 -0
  110. package/build/lazyLoad/downloadResponse.js.map +1 -0
  111. package/build/lazyLoad/generic/generic_crawlPages.js +186 -0
  112. package/build/lazyLoad/generic/generic_crawlPages.js.map +1 -0
  113. package/build/lazyLoad/generic/generic_downloadFiles.js +81 -0
  114. package/build/lazyLoad/generic/generic_downloadFiles.js.map +1 -0
  115. package/build/lazyLoad/generic/generic_extractLinks.js +79 -0
  116. package/build/lazyLoad/generic/generic_extractLinks.js.map +1 -0
  117. package/build/lazyLoad/generic/generic_getScriptTags.js +152 -0
  118. package/build/lazyLoad/generic/generic_getScriptTags.js.map +1 -0
  119. package/build/lazyLoad/generic/generic_importMapDiscovery.js +87 -0
  120. package/build/lazyLoad/generic/generic_importMapDiscovery.js.map +1 -0
  121. package/build/lazyLoad/generic/generic_resolveScope.js +61 -0
  122. package/build/lazyLoad/generic/generic_resolveScope.js.map +1 -0
  123. package/build/lazyLoad/generic/generic_scanAttributesForJs.js +122 -0
  124. package/build/lazyLoad/generic/generic_scanAttributesForJs.js.map +1 -0
  125. package/build/lazyLoad/generic/generic_stringsDiscovery.js +103 -0
  126. package/build/lazyLoad/generic/generic_stringsDiscovery.js.map +1 -0
  127. package/build/lazyLoad/generic/generic_webpackChunkPaths.js +56 -0
  128. package/build/lazyLoad/generic/generic_webpackChunkPaths.js.map +1 -0
  129. package/build/lazyLoad/globals.js +35 -0
  130. package/build/lazyLoad/globals.js.map +1 -1
  131. package/build/lazyLoad/index.js +311 -175
  132. package/build/lazyLoad/index.js.map +1 -1
  133. package/build/lazyLoad/methodFilter.js +2 -0
  134. package/build/lazyLoad/methodFilter.js.map +1 -1
  135. package/build/lazyLoad/next_js/NextJsCrawler.js +39 -14
  136. package/build/lazyLoad/next_js/NextJsCrawler.js.map +1 -1
  137. package/build/lazyLoad/next_js/next_GetJSScript.js +3 -3
  138. package/build/lazyLoad/next_js/next_GetJSScript.js.map +1 -1
  139. package/build/lazyLoad/next_js/next_GetLazyResourcesBuildManifestJs.js +4 -4
  140. package/build/lazyLoad/next_js/next_GetLazyResourcesBuildManifestJs.js.map +1 -1
  141. package/build/lazyLoad/next_js/next_GetLazyResourcesWebpackJs.js +21 -20
  142. package/build/lazyLoad/next_js/next_GetLazyResourcesWebpackJs.js.map +1 -1
  143. package/build/lazyLoad/next_js/next_SubsequentRequests.js +100 -99
  144. package/build/lazyLoad/next_js/next_SubsequentRequests.js.map +1 -1
  145. package/build/lazyLoad/next_js/next_bruteForceJsFiles.js +1 -1
  146. package/build/lazyLoad/next_js/next_bruteForceJsFiles.js.map +1 -1
  147. package/build/lazyLoad/next_js/next_buildId.js +2 -2
  148. package/build/lazyLoad/next_js/next_buildId.js.map +1 -1
  149. package/build/lazyLoad/next_js/next_getClientSidePaths.js +2 -2
  150. package/build/lazyLoad/next_js/next_getClientSidePaths.js.map +1 -1
  151. package/build/lazyLoad/next_js/next_parseLayoutJs.js +6 -6
  152. package/build/lazyLoad/next_js/next_parseLayoutJs.js.map +1 -1
  153. package/build/lazyLoad/next_js/next_promiseResolve.js +1 -1
  154. package/build/lazyLoad/next_js/next_promiseResolve.js.map +1 -1
  155. package/build/lazyLoad/next_js/next_routerStateForge.js +341 -0
  156. package/build/lazyLoad/next_js/next_routerStateForge.js.map +1 -0
  157. package/build/lazyLoad/next_js/next_scriptTagsSubsequentRequests.js +1 -1
  158. package/build/lazyLoad/next_js/next_scriptTagsSubsequentRequests.js.map +1 -1
  159. package/build/lazyLoad/next_js/next_serverActionIdScan.js +77 -0
  160. package/build/lazyLoad/next_js/next_serverActionIdScan.js.map +1 -0
  161. package/build/lazyLoad/nuxt_js/nuxt_astParse.js +15 -13
  162. package/build/lazyLoad/nuxt_js/nuxt_astParse.js.map +1 -1
  163. package/build/lazyLoad/nuxt_js/nuxt_getBuildsManifest.js +2 -2
  164. package/build/lazyLoad/nuxt_js/nuxt_getBuildsManifest.js.map +1 -1
  165. package/build/lazyLoad/nuxt_js/nuxt_getFromPageSource.js +3 -3
  166. package/build/lazyLoad/nuxt_js/nuxt_getFromPageSource.js.map +1 -1
  167. package/build/lazyLoad/nuxt_js/nuxt_stringAnalysisJSFiles.js +2 -2
  168. package/build/lazyLoad/nuxt_js/nuxt_stringAnalysisJSFiles.js.map +1 -1
  169. package/build/lazyLoad/outputPath.js +92 -0
  170. package/build/lazyLoad/outputPath.js.map +1 -0
  171. package/build/lazyLoad/react/react_followImports.js +15 -5
  172. package/build/lazyLoad/react/react_followImports.js.map +1 -1
  173. package/build/lazyLoad/react/react_getScriptTags.js +11 -6
  174. package/build/lazyLoad/react/react_getScriptTags.js.map +1 -1
  175. package/build/lazyLoad/react/react_sourcemapUrls.js +3 -2
  176. package/build/lazyLoad/react/react_sourcemapUrls.js.map +1 -1
  177. package/build/lazyLoad/react/react_webpackChunkPaths.js +12 -203
  178. package/build/lazyLoad/react/react_webpackChunkPaths.js.map +1 -1
  179. package/build/lazyLoad/researchUtils.js +15 -0
  180. package/build/lazyLoad/researchUtils.js.map +1 -0
  181. package/build/lazyLoad/shared/webpackChunkParsers.js +218 -0
  182. package/build/lazyLoad/shared/webpackChunkParsers.js.map +1 -0
  183. package/build/lazyLoad/stagnation/stagnationMonitor.js +63 -0
  184. package/build/lazyLoad/stagnation/stagnationMonitor.js.map +1 -0
  185. package/build/lazyLoad/svelte/svelte_discoverPagesFromJs.js +1 -0
  186. package/build/lazyLoad/svelte/svelte_discoverPagesFromJs.js.map +1 -1
  187. package/build/lazyLoad/svelte/svelte_getFromPageSource.js +5 -5
  188. package/build/lazyLoad/svelte/svelte_getFromPageSource.js.map +1 -1
  189. package/build/lazyLoad/svelte/svelte_getVersionJson.js +2 -2
  190. package/build/lazyLoad/svelte/svelte_getVersionJson.js.map +1 -1
  191. package/build/lazyLoad/svelte/svelte_recursivePageCrawl.js +6 -6
  192. package/build/lazyLoad/svelte/svelte_recursivePageCrawl.js.map +1 -1
  193. package/build/lazyLoad/svelte/svelte_stringAnalysisJSFiles.js +2 -2
  194. package/build/lazyLoad/svelte/svelte_stringAnalysisJSFiles.js.map +1 -1
  195. package/build/lazyLoad/techDetect/checkAngularJS.js +1 -1
  196. package/build/lazyLoad/techDetect/checkAngularJS.js.map +1 -1
  197. package/build/lazyLoad/techDetect/checkNuxtJS.js +3 -3
  198. package/build/lazyLoad/techDetect/checkNuxtJS.js.map +1 -1
  199. package/build/lazyLoad/techDetect/checkSvelte.js +0 -1
  200. package/build/lazyLoad/techDetect/checkSvelte.js.map +1 -1
  201. package/build/lazyLoad/techDetect/checkVueJS.js +6 -6
  202. package/build/lazyLoad/techDetect/checkVueJS.js.map +1 -1
  203. package/build/lazyLoad/techDetect/index.js +106 -60
  204. package/build/lazyLoad/techDetect/index.js.map +1 -1
  205. package/build/lazyLoad/vue/vue_RuntimeJs.js +20 -15
  206. package/build/lazyLoad/vue/vue_RuntimeJs.js.map +1 -1
  207. package/build/lazyLoad/vue/vue_SingleJsFileOnHome.js +10 -5
  208. package/build/lazyLoad/vue/vue_SingleJsFileOnHome.js.map +1 -1
  209. package/build/lazyLoad/vue/vue_discoverJsFiles.js +20 -17
  210. package/build/lazyLoad/vue/vue_discoverJsFiles.js.map +1 -1
  211. package/build/lazyLoad/vue/vue_getClientSidePaths.js +70 -46
  212. package/build/lazyLoad/vue/vue_getClientSidePaths.js.map +1 -1
  213. package/build/lazyLoad/vue/vue_jsImports.js +3 -2
  214. package/build/lazyLoad/vue/vue_jsImports.js.map +1 -1
  215. package/build/lazyLoad/vue/vue_pageSrc.js +3 -2
  216. package/build/lazyLoad/vue/vue_pageSrc.js.map +1 -1
  217. package/build/lazyLoad/vue/vue_reconstructSourceMaps.js +6 -5
  218. package/build/lazyLoad/vue/vue_reconstructSourceMaps.js.map +1 -1
  219. package/build/lazyLoad/vue/vue_recursiveClientSidePathDownload.js +10 -21
  220. package/build/lazyLoad/vue/vue_recursiveClientSidePathDownload.js.map +1 -1
  221. package/build/lazyLoad/vue/vue_severalJsFilesHome.js +5 -4
  222. package/build/lazyLoad/vue/vue_severalJsFilesHome.js.map +1 -1
  223. package/build/lazyLoad/vue/vue_stringJsFiles.js +28 -25
  224. package/build/lazyLoad/vue/vue_stringJsFiles.js.map +1 -1
  225. package/build/lazyLoad/vue/vue_viteMapDeps.js +8 -2
  226. package/build/lazyLoad/vue/vue_viteMapDeps.js.map +1 -1
  227. package/build/load/index.js +8 -7
  228. package/build/load/index.js.map +1 -1
  229. package/build/map/angular_js/getAngularConnections.js +6 -6
  230. package/build/map/angular_js/getAngularConnections.js.map +1 -1
  231. package/build/map/graphql/resolveGraphql.js +6 -6
  232. package/build/map/graphql/resolveGraphql.js.map +1 -1
  233. package/build/map/index.js +17 -17
  234. package/build/map/index.js.map +1 -1
  235. package/build/map/interactive-mode/commandHandler.js +278 -0
  236. package/build/map/interactive-mode/commandHandler.js.map +1 -0
  237. package/build/map/interactive-mode/commandHelpers.js +189 -0
  238. package/build/map/interactive-mode/commandHelpers.js.map +1 -0
  239. package/build/map/interactive-mode/esqueryGen.js.map +1 -0
  240. package/build/map/interactive-mode/helpMenu.js +11 -0
  241. package/build/map/interactive-mode/helpMenu.js.map +1 -0
  242. package/build/map/interactive-mode/inputPatch.js.map +1 -0
  243. package/build/map/interactive-mode/interactive.js +71 -0
  244. package/build/map/interactive-mode/interactive.js.map +1 -0
  245. package/build/map/interactive-mode/keybindings.js.map +1 -0
  246. package/build/map/interactive-mode/printer.js.map +1 -0
  247. package/build/map/interactive-mode/ui.js.map +1 -0
  248. package/build/map/next_js/getAxiosInstances.js +5 -5
  249. package/build/map/next_js/getAxiosInstances.js.map +1 -1
  250. package/build/map/next_js/getExports.js +4 -4
  251. package/build/map/next_js/getExports.js.map +1 -1
  252. package/build/map/next_js/getFetchInstances.js +10 -10
  253. package/build/map/next_js/getFetchInstances.js.map +1 -1
  254. package/build/map/next_js/getTurbopackConnections.js +8 -8
  255. package/build/map/next_js/getTurbopackConnections.js.map +1 -1
  256. package/build/map/next_js/getWebpackConnections.js +27 -16
  257. package/build/map/next_js/getWebpackConnections.js.map +1 -1
  258. package/build/map/next_js/interactive.js +3 -65
  259. package/build/map/next_js/interactive.js.map +1 -1
  260. package/build/map/next_js/interactive_helpers/commandHandler.js +38 -290
  261. package/build/map/next_js/interactive_helpers/commandHandler.js.map +1 -1
  262. package/build/map/next_js/interactive_helpers/commandHelpers.js +0 -184
  263. package/build/map/next_js/interactive_helpers/commandHelpers.js.map +1 -1
  264. package/build/map/next_js/interactive_helpers/helpMenu.js +2 -10
  265. package/build/map/next_js/interactive_helpers/helpMenu.js.map +1 -1
  266. package/build/map/next_js/resolveAxios.js +6 -6
  267. package/build/map/next_js/resolveAxios.js.map +1 -1
  268. package/build/map/next_js/resolveAxiosHelpers/findAxiosClients.js +4 -4
  269. package/build/map/next_js/resolveAxiosHelpers/findAxiosClients.js.map +1 -1
  270. package/build/map/next_js/resolveAxiosHelpers/findAxiosInstance.js +2 -2
  271. package/build/map/next_js/resolveAxiosHelpers/findAxiosInstance.js.map +1 -1
  272. package/build/map/next_js/resolveAxiosHelpers/findCrossChunkParams.js +5 -5
  273. package/build/map/next_js/resolveAxiosHelpers/findCrossChunkParams.js.map +1 -1
  274. package/build/map/next_js/resolveAxiosHelpers/handleAxiosCreate.js +10 -10
  275. package/build/map/next_js/resolveAxiosHelpers/handleAxiosCreate.js.map +1 -1
  276. package/build/map/next_js/resolveAxiosHelpers/handleZDotCreate.js +13 -9
  277. package/build/map/next_js/resolveAxiosHelpers/handleZDotCreate.js.map +1 -1
  278. package/build/map/next_js/resolveAxiosHelpers/processAxiosCall.js +12 -8
  279. package/build/map/next_js/resolveAxiosHelpers/processAxiosCall.js.map +1 -1
  280. package/build/map/next_js/resolveAxiosHelpers/processDirectAxiosCall.js +12 -8
  281. package/build/map/next_js/resolveAxiosHelpers/processDirectAxiosCall.js.map +1 -1
  282. package/build/map/next_js/resolveAxiosHelpers/processExportedEndpoints.js +11 -11
  283. package/build/map/next_js/resolveAxiosHelpers/processExportedEndpoints.js.map +1 -1
  284. package/build/map/next_js/resolveAxiosHelpers/traceAxiosInstanceExports.js +16 -16
  285. package/build/map/next_js/resolveAxiosHelpers/traceAxiosInstanceExports.js.map +1 -1
  286. package/build/map/next_js/resolveFetch.js +23 -23
  287. package/build/map/next_js/resolveFetch.js.map +1 -1
  288. package/build/map/next_js/resolveNewRequest.js +10 -10
  289. package/build/map/next_js/resolveNewRequest.js.map +1 -1
  290. package/build/map/next_js/resolveServerActions.js +4 -4
  291. package/build/map/next_js/resolveServerActions.js.map +1 -1
  292. package/build/map/next_js/utils.js +8 -2
  293. package/build/map/next_js/utils.js.map +1 -1
  294. package/build/map/react_js/getReactConnections.js +21 -14
  295. package/build/map/react_js/getReactConnections.js.map +1 -1
  296. package/build/map/svelte_js/interactive.js +3 -54
  297. package/build/map/svelte_js/interactive.js.map +1 -1
  298. package/build/map/vue_js/getViteConnections.js +23 -16
  299. package/build/map/vue_js/getViteConnections.js.map +1 -1
  300. package/build/map/vue_js/interactive.js +3 -63
  301. package/build/map/vue_js/interactive.js.map +1 -1
  302. package/build/map/vue_js/interactive_helpers/commandHandler.js +34 -283
  303. package/build/map/vue_js/interactive_helpers/commandHandler.js.map +1 -1
  304. package/build/map/vue_js/interactive_helpers/helpMenu.js +2 -10
  305. package/build/map/vue_js/interactive_helpers/helpMenu.js.map +1 -1
  306. package/build/map/vue_js/taint_utils.js +1 -1
  307. package/build/map/vue_js/taint_utils.js.map +1 -1
  308. package/build/map/vue_js/vue_resolveFetch.js +12 -12
  309. package/build/map/vue_js/vue_resolveFetch.js.map +1 -1
  310. package/build/map/vue_js/vue_resolveHttpClient.js +18 -18
  311. package/build/map/vue_js/vue_resolveHttpClient.js.map +1 -1
  312. package/build/map/vue_js/vue_resolveXhr.js +11 -11
  313. package/build/map/vue_js/vue_resolveXhr.js.map +1 -1
  314. package/build/mcp/chatOneShot.js +7 -7
  315. package/build/mcp/chatOneShot.js.map +1 -1
  316. package/build/mcp/claudeCodeCreds.js +5 -5
  317. package/build/mcp/claudeCodeCreds.js.map +1 -1
  318. package/build/mcp/cli.js +36 -35
  319. package/build/mcp/cli.js.map +1 -1
  320. package/build/mcp/config.js +4 -4
  321. package/build/mcp/config.js.map +1 -1
  322. package/build/mcp/index.js +7 -7
  323. package/build/mcp/index.js.map +1 -1
  324. package/build/mcp/mcpServer.js +3 -2
  325. package/build/mcp/mcpServer.js.map +1 -1
  326. package/build/mcp/skills.js +1 -0
  327. package/build/mcp/skills.js.map +1 -1
  328. package/build/mcp/tools.js +5 -4
  329. package/build/mcp/tools.js.map +1 -1
  330. package/build/proxy/checkFeasibility.js +8 -4
  331. package/build/proxy/checkFeasibility.js.map +1 -1
  332. package/build/proxy/checkFireWallBlocking.js +23 -13
  333. package/build/proxy/checkFireWallBlocking.js.map +1 -1
  334. package/build/proxy/detectBlockedResponse.js +205 -0
  335. package/build/proxy/detectBlockedResponse.js.map +1 -0
  336. package/build/proxy/genReq.js +434 -127
  337. package/build/proxy/genReq.js.map +1 -1
  338. package/build/proxy/index.js +3 -3
  339. package/build/proxy/index.js.map +1 -1
  340. package/build/proxy/oxylabsFallback.js +110 -0
  341. package/build/proxy/oxylabsFallback.js.map +1 -0
  342. package/build/proxy/proxyFeasibilityRequest.js +11 -9
  343. package/build/proxy/proxyFeasibilityRequest.js.map +1 -1
  344. package/build/refactor/index.js +83 -79
  345. package/build/refactor/index.js.map +1 -1
  346. package/build/refactor/next/index.js +69 -26
  347. package/build/refactor/next/index.js.map +1 -1
  348. package/build/refactor/next/transform.js +11 -4
  349. package/build/refactor/next/transform.js.map +1 -1
  350. package/build/refactor/next/validator.js +7 -7
  351. package/build/refactor/next/validator.js.map +1 -1
  352. package/build/refactor/react/index.js +13 -13
  353. package/build/refactor/react/index.js.map +1 -1
  354. package/build/refactor/react/validator.js +7 -7
  355. package/build/refactor/react/validator.js.map +1 -1
  356. package/build/refactor/react-vite/index.js +3 -3
  357. package/build/refactor/react-vite/index.js.map +1 -1
  358. package/build/refactor/remote/hf-client.js +1 -0
  359. package/build/refactor/remote/hf-client.js.map +1 -1
  360. package/build/refactor/remote/version-detect.js +12 -12
  361. package/build/refactor/remote/version-detect.js.map +1 -1
  362. package/build/refactor/vue/index.js +6 -6
  363. package/build/refactor/vue/index.js.map +1 -1
  364. package/build/refactor/vue/vite.js +6 -6
  365. package/build/refactor/vue/vite.js.map +1 -1
  366. package/build/report/index.js +30 -8
  367. package/build/report/index.js.map +1 -1
  368. package/build/report/swaggerJacker.js +63 -0
  369. package/build/report/swaggerJacker.js.map +1 -0
  370. package/build/report/utility/genHtml.js +7 -7
  371. package/build/report/utility/genHtml.js.map +1 -1
  372. package/build/report/utility/populateDb/populateAnalysisFindings.js +2 -2
  373. package/build/report/utility/populateDb/populateAnalysisFindings.js.map +1 -1
  374. package/build/report/utility/populateDb/populateEndpoints.js +3 -3
  375. package/build/report/utility/populateDb/populateEndpoints.js.map +1 -1
  376. package/build/report/utility/populateDb/populateMappedJson.js +2 -2
  377. package/build/report/utility/populateDb/populateMappedJson.js.map +1 -1
  378. package/build/report/utility/populateDb/populateMappedOpenapi.js +3 -3
  379. package/build/report/utility/populateDb/populateMappedOpenapi.js.map +1 -1
  380. package/build/run/bundler-detect.js +45 -9
  381. package/build/run/bundler-detect.js.map +1 -1
  382. package/build/run/cancellableStep.js +27 -0
  383. package/build/run/cancellableStep.js.map +1 -0
  384. package/build/run/dashboard/dashboardHtml.js +150 -0
  385. package/build/run/dashboard/dashboardHtml.js.map +1 -0
  386. package/build/run/dashboard/fsBrowser.js +43 -0
  387. package/build/run/dashboard/fsBrowser.js.map +1 -0
  388. package/build/run/dashboard/server.js +123 -0
  389. package/build/run/dashboard/server.js.map +1 -0
  390. package/build/run/dashboard/state.js +97 -0
  391. package/build/run/dashboard/state.js.map +1 -0
  392. package/build/run/index.js +239 -204
  393. package/build/run/index.js.map +1 -1
  394. package/build/run/interruptHandler.js +18 -0
  395. package/build/run/interruptHandler.js.map +1 -1
  396. package/build/run/outputDirectory.js +377 -0
  397. package/build/run/outputDirectory.js.map +1 -0
  398. package/build/sourcemaps/index.js +116 -29
  399. package/build/sourcemaps/index.js.map +1 -1
  400. package/build/strings/index.js +38 -28
  401. package/build/strings/index.js.map +1 -1
  402. package/build/strings/openapi.js +4 -4
  403. package/build/strings/openapi.js.map +1 -1
  404. package/build/strings/permutate.js +4 -4
  405. package/build/strings/permutate.js.map +1 -1
  406. package/build/strings/secrets.js +1 -0
  407. package/build/strings/secrets.js.map +1 -1
  408. package/build/strings/trufflehog.js +66 -19
  409. package/build/strings/trufflehog.js.map +1 -1
  410. package/build/strings/trufflehogConfig.js +36 -0
  411. package/build/strings/trufflehogConfig.js.map +1 -0
  412. package/build/strings/trufflehogDownload.js +115 -0
  413. package/build/strings/trufflehogDownload.js.map +1 -0
  414. package/build/utility/ai.js +33 -4
  415. package/build/utility/ai.js.map +1 -1
  416. package/build/utility/banner.js +4 -3
  417. package/build/utility/banner.js.map +1 -1
  418. package/build/utility/configureSandbox.js +2 -2
  419. package/build/utility/configureSandbox.js.map +1 -1
  420. package/build/utility/downloadProgress.js +99 -0
  421. package/build/utility/downloadProgress.js.map +1 -0
  422. package/build/utility/globals.js +19 -11
  423. package/build/utility/globals.js.map +1 -1
  424. package/build/utility/heap.js +2 -1
  425. package/build/utility/heap.js.map +1 -1
  426. package/build/utility/makeReq.js +490 -257
  427. package/build/utility/makeReq.js.map +1 -1
  428. package/build/utility/openapiGenerator.js +2 -2
  429. package/build/utility/openapiGenerator.js.map +1 -1
  430. package/build/utility/printMsg.js +53 -0
  431. package/build/utility/printMsg.js.map +1 -0
  432. package/build/utility/progressLog.js +68 -7
  433. package/build/utility/progressLog.js.map +1 -1
  434. package/build/utility/resolvePath.js +2 -1
  435. package/build/utility/resolvePath.js.map +1 -1
  436. package/build/utility/ruleVersionMap.js +73 -0
  437. package/build/utility/ruleVersionMap.js.map +1 -0
  438. package/build/utility/targetInputs.js +177 -0
  439. package/build/utility/targetInputs.js.map +1 -0
  440. package/build/utility/urlUtils.js +37 -1
  441. package/build/utility/urlUtils.js.map +1 -1
  442. package/config.dist.yaml +251 -0
  443. package/contributing/testing.md +106 -0
  444. package/eslint.config.js +24 -0
  445. package/package.json +22 -5
  446. package/scripts/exploit-smoke-test.js +82 -0
  447. package/scripts/framework-detect-smoke-test.js +64 -0
  448. package/scripts/postinstall-completion.mjs +40 -0
  449. package/scripts/smoke-test.js +12 -0
  450. package/build/lazyLoad/downloadLoadedJsUtil.js +0 -98
  451. package/build/lazyLoad/downloadLoadedJsUtil.js.map +0 -1
  452. package/build/map/next_js/interactive_helpers/esqueryGen.js.map +0 -1
  453. package/build/map/next_js/interactive_helpers/inputPatch.js.map +0 -1
  454. package/build/map/next_js/interactive_helpers/keybindings.js.map +0 -1
  455. package/build/map/next_js/interactive_helpers/printer.js.map +0 -1
  456. package/build/map/next_js/interactive_helpers/ui.js.map +0 -1
  457. /package/build/map/{next_js/interactive_helpers → interactive-mode}/esqueryGen.js +0 -0
  458. /package/build/map/{next_js/interactive_helpers → interactive-mode}/inputPatch.js +0 -0
  459. /package/build/map/{next_js/interactive_helpers → interactive-mode}/keybindings.js +0 -0
  460. /package/build/map/{next_js/interactive_helpers → interactive-mode}/printer.js +0 -0
  461. /package/build/map/{next_js/interactive_helpers → interactive-mode}/ui.js +0 -0
@@ -14,19 +14,26 @@ import * as globalsUtil from "../utility/globals.js";
14
14
  import * as fs from "fs";
15
15
  import lazyLoad from "../lazyLoad/index.js";
16
16
  import chalk from "chalk";
17
- import CONFIG from "../globalConfig.js";
18
17
  import analyze from "../analyze/index.js";
19
18
  import report from "../report/index.js";
20
19
  import refactor from "../refactor/index.js";
21
20
  import initGlobalReportDb from "../report/utility/initGlobalReportDb.js";
22
21
  import mergeDomainIntoGlobalDb from "../report/utility/mergeDomainIntoGlobalDb.js";
23
- import { clearJsUrls, clearJsonUrls, getJsUrls } from "../lazyLoad/globals.js";
22
+ import { clearJsUrls, clearJsonUrls, clearJsFileHashCounts, getJsUrls } from "../lazyLoad/globals.js";
24
23
  import path from "path";
25
24
  import { installSigintHandler, removeSigintHandler, getSkipStepPromise, resetSkipStep, shouldSkipTarget, resetSkipTarget, waitForPendingInterrupt, } from "./interruptHandler.js";
26
25
  import { detectBundler } from "./bundler-detect.js";
26
+ import { printMsg, MSG, setHeaderListener } from "../utility/printMsg.js";
27
27
  import configureProxy from "../utility/configureProxy.js";
28
+ import { getOxylabsFallbackConfiguration } from "../proxy/oxylabsFallback.js";
28
29
  import { probeFeasibility } from "../proxy/checkFeasibility.js";
29
30
  import { getResolvedProxyConfigFromGlobals } from "../utility/makeReq.js";
31
+ import { resolveHostOutputDirectory } from "../lazyLoad/outputPath.js";
32
+ import { awaitCancellableStep } from "./cancellableStep.js";
33
+ import { resolveTargetInputs } from "../utility/targetInputs.js";
34
+ import { clearRunOutputDirectory, getBatchTargetDirectoryName, reserveRunOutputDirectory } from "./outputDirectory.js";
35
+ import { startDashboardServer } from "./dashboard/server.js";
36
+ import * as dashboardState from "./dashboard/state.js";
30
37
  /**
31
38
  * Determines the directory for a Content Delivery Network (CDN) if used by the target.
32
39
  *
@@ -37,17 +44,16 @@ import { getResolvedProxyConfigFromGlobals } from "../utility/makeReq.js";
37
44
  * @param outputDir - The base output directory
38
45
  * @returns Promise that resolves to the path of the CDN directory or undefined if no CDN is detected
39
46
  */
40
- const getCdnDir = (host, outputDir) => __awaiter(void 0, void 0, void 0, function* () {
47
+ const getCdnDir = (host, outputDir, isBatch) => __awaiter(void 0, void 0, void 0, function* () {
41
48
  // get the JS URLs
42
49
  let cdnDir;
43
50
  for (const url of getJsUrls()) {
44
51
  if (url.includes("_next/static/chunks")) {
45
52
  // check if the host and url.host match
46
- const urlHostDir = new URL(url).host.replace(":", "_"); // e.g. example.com_8443
47
53
  const urlHost = new URL(url).host; // e.g. example.com:8443
48
54
  const initialHost = new URL(host).host; // e.g. example.com:443
49
55
  if (urlHost !== initialHost) {
50
- cdnDir = path.join(outputDir, urlHostDir);
56
+ cdnDir = resolveHostOutputDirectory(outputDir, urlHost, isBatch);
51
57
  break;
52
58
  }
53
59
  }
@@ -74,11 +80,12 @@ const getCdnDir = (host, outputDir) => __awaiter(void 0, void 0, void 0, functio
74
80
  */
75
81
  const processUrl = (url_1, outputDir_1, workingDir_1, cmd_1, isBatch_1, ...args_1) => __awaiter(void 0, [url_1, outputDir_1, workingDir_1, cmd_1, isBatch_1, ...args_1], void 0, function* (url, outputDir, workingDir, cmd, isBatch, includeMethods = [], excludeMethods = []) {
76
82
  var _a, _b, _c, _d;
77
- const targetHost = new URL(url).host.replace(":", "_");
78
- console.log(chalk.bgGreenBright(`[+] Starting analysis for ${url}...`));
83
+ const targetHost = new URL(url).host;
84
+ printMsg(MSG.Run, `[+] Starting analysis for ${url}...`);
79
85
  if (isBatch) {
80
86
  clearJsUrls();
81
87
  clearJsonUrls();
88
+ clearJsFileHashCounts();
82
89
  globalsUtil.clearOpenapiOutput();
83
90
  }
84
91
  if (cmd.proxyWafFallback && cmd._proxyConfigured) {
@@ -89,42 +96,39 @@ const processUrl = (url_1, outputDir_1, workingDir_1, cmd_1, isBatch_1, ...args_
89
96
  outcome = yield probeFeasibility(resolved, url);
90
97
  }
91
98
  catch (error) {
92
- console.error(chalk.bgRed(`[!] Proxy WAF fallback check failed: ${error}. ${isBatch ? "Skipping this target." : "Quitting."}`));
99
+ printMsg(MSG.Err, `[!] Proxy WAF fallback check failed: ${error}. ${isBatch ? "Skipping this target." : "Quitting."}`);
93
100
  if (isBatch)
94
101
  return;
95
102
  process.exit(29);
96
103
  }
97
- console.log(outcome.code === 0 ? chalk.green(outcome.message) : chalk.yellow(outcome.message));
104
+ printMsg(outcome.code === 0 ? MSG.Run : MSG.Warn, outcome.message);
98
105
  if (outcome.code === 27) {
99
106
  // no firewall detected without a proxy - don't use it for this target
100
107
  globalsUtil.setUseProxy(false);
101
108
  }
102
109
  else if (outcome.code === 28) {
103
- console.error(chalk.bgRed(`[!] Proxy could not bypass the firewall for this target. ${isBatch ? "Skipping this target." : "Quitting."}`));
110
+ printMsg(MSG.Err, `[!] Proxy could not bypass the firewall for this target. ${isBatch ? "Skipping this target." : "Quitting."}`);
104
111
  if (isBatch)
105
112
  return;
106
113
  process.exit(29);
107
114
  }
108
115
  // outcome.code === 0: firewall present, proxy bypasses it - keep using the proxy
109
116
  }
110
- console.log(chalk.bgCyan("[1/8] Running lazyload to download JavaScript files..."));
117
+ printMsg(MSG.Header, "[1/8] Running lazyload to download JavaScript files...");
111
118
  resetSkipStep();
112
- yield Promise.race([
113
- lazyLoad(url, outputDir, cmd.strictScope, cmd.scope.split(","), cmd.threads, false, "", cmd.insecure, false, cmd.sourcemapDir, cmd.research, cmd.researchOutput, Number(cmd.maxIterations), Number(cmd.maxJsSize), Number(cmd.lazyloadTimeout) * 60 * 1000, Number(cmd.maxPages), includeMethods, excludeMethods, Number(cmd.detectionTimeout) * 1000),
114
- getSkipStepPromise(),
115
- ]);
116
- console.log(chalk.bgGreen("[+] Lazyload complete."));
119
+ yield awaitCancellableStep((signal) => lazyLoad(url, outputDir, cmd.strictScope, cmd.scope.split(","), cmd.threads, false, "", cmd.insecure, false, cmd.sourcemapDir, cmd.research, cmd.researchOutput, Number(cmd.maxIterations), Number(cmd.maxJsSize), Number(cmd.lazyloadTimeout) * 60 * 1000, Number(cmd.maxPages), includeMethods, excludeMethods, Number(cmd.detectionTimeout) * 1000, signal, isBatch, Number(cmd.maxRedirects), cmd.strings, Number(cmd.stringsMaxIterations), Number(cmd.stagnationTimein) * 60 * 1000, Number(cmd.stagnationPercentage), Number(cmd.stagnationMonitor) * 60 * 1000, Number(cmd.rscParamBruteforceLimit)), getSkipStepPromise());
120
+ printMsg(MSG.Run, "[+] Lazyload complete.");
117
121
  if (shouldSkipTarget())
118
122
  return;
119
123
  if (globalsUtil.getTech() === "") {
120
- console.error(chalk.bgRed(`[!] Technology not detected. ${isBatch ? "Skipping this target." : "Quitting."}`));
124
+ printMsg(MSG.Err, `[!] Technology not detected. ${isBatch ? "Skipping this target." : "Quitting."}`);
121
125
  if (isBatch) {
122
126
  return;
123
127
  }
124
128
  process.exit(10);
125
129
  }
126
130
  if (!["next", "vue", "nuxt", "react", "svelte", "angular"].includes(globalsUtil.getTech())) {
127
- console.log(chalk.bgYellow(`[!] The tool supports Next.JS, Vue.JS, Nuxt.JS, React, Svelte/Astro, and Angular in the run module. For ${globalsUtil.getTech()}, only downloading JS files is supported`));
131
+ printMsg(MSG.Warn, `[!] The tool supports Next.JS, Vue.JS, Nuxt.JS, React, Svelte/Astro, and Angular in the run module. For ${globalsUtil.getTech()}, only downloading JS files is supported`);
128
132
  return;
129
133
  }
130
134
  // Capture the tech here — subsequent lazyload passes (steps 3, 4.5) re-run framework
@@ -140,7 +144,7 @@ const processUrl = (url_1, outputDir_1, workingDir_1, cmd_1, isBatch_1, ...args_
140
144
  const reportDbFile = isBatch ? `${workingDir}/js-recon.db` : "js-recon.db";
141
145
  const reportFile = isBatch ? `${workingDir}/report` : "report";
142
146
  const endpointsFile = isBatch ? `${workingDir}/endpoints` : "endpoints";
143
- console.log(chalk.bgCyan("[2/4] Running map to find functions and API calls..."));
147
+ printMsg(MSG.Header, "[2/4] Running map to find functions and API calls...");
144
148
  globalsUtil.setOpenapi(true);
145
149
  if (isBatch) {
146
150
  globalsUtil.setOpenapiOutputFile(openapiFile);
@@ -155,46 +159,45 @@ const processUrl = (url_1, outputDir_1, workingDir_1, cmd_1, isBatch_1, ...args_
155
159
  map(outputDir, mappedFileReact, ["json"], "react", false, false, cmd.command || []),
156
160
  getSkipStepPromise(),
157
161
  ]);
158
- console.log(chalk.bgGreen("[+] Map complete."));
162
+ printMsg(MSG.Run, "[+] Map complete.");
159
163
  if (shouldSkipTarget())
160
164
  return;
161
- console.log(chalk.bgCyan("[3/4] Running analyze..."));
165
+ printMsg(MSG.Header, "[3/4] Running analyze...");
162
166
  resetSkipStep();
163
- // @ts-ignore
164
167
  yield Promise.race([
165
- analyze(cmd.rules || "", mappedJsonFileReact, "react", false, openapiFile, false, analyzeFile, !!cmd.disableRulesVersionCheck),
168
+ analyze(cmd.rules || "", mappedJsonFileReact, "react", false, openapiFile, false, analyzeFile, !!cmd.disableRulesVersionCheck, false, false),
166
169
  getSkipStepPromise(),
167
170
  ]);
168
- console.log(chalk.bgGreen("[+] Analyze complete."));
171
+ printMsg(MSG.Run, "[+] Analyze complete.");
169
172
  if (shouldSkipTarget())
170
173
  return;
171
- console.log(chalk.bgCyan("[4/4] Running report module..."));
174
+ printMsg(MSG.Header, "[4/4] Running report module...");
172
175
  const endpointsJson = `${endpointsFile}.json`;
173
176
  if (!fs.existsSync(endpointsJson)) {
174
177
  fs.writeFileSync(endpointsJson, "[]");
175
178
  }
176
179
  resetSkipStep();
177
180
  yield Promise.race([
178
- report(reportDbFile, mappedJsonFileReact, analyzeFile, endpointsJson, openapiFile, reportFile),
181
+ report(reportDbFile, mappedJsonFileReact, analyzeFile, endpointsJson, openapiFile, reportFile, cmd.sj, cmd.sjBin, cmd.sjArgs),
179
182
  getSkipStepPromise(),
180
183
  ]);
181
- console.log(chalk.bgGreen("[+] Report complete."));
184
+ printMsg(MSG.Run, "[+] Report complete.");
182
185
  if (shouldSkipTarget())
183
186
  return;
184
187
  if (!cmd.disableRefactor) {
185
- console.log(chalk.bgCyan("[*] Detecting bundler via CS-MAST-S for refactor..."));
188
+ printMsg(MSG.Header, "[*] Detecting bundler via CS-MAST-S for refactor...");
186
189
  const detectedBundlerTechReact = yield detectBundler(mappedJsonFileReact, "react", Number((_a = cmd.csMastTechDetectThreshold) !== null && _a !== void 0 ? _a : 50));
187
190
  if (detectedBundlerTechReact) {
188
191
  const refactorOutputDirReact = isBatch ? `${workingDir}/refactored` : "refactored";
189
192
  if (fs.existsSync(refactorOutputDirReact))
190
193
  fs.rmSync(refactorOutputDirReact, { recursive: true });
191
- console.log(chalk.bgCyan(`[*] Running refactor (${detectedBundlerTechReact})...`));
194
+ printMsg(MSG.Header, `[*] Running refactor (${detectedBundlerTechReact})...`);
192
195
  // Vendor chunks may have been downloaded under a different host than the target
193
196
  // (CDN) — resolve the assets dir from an actual downloaded JS URL's host instead
194
197
  // of always assuming targetHost, mirroring getCdnDir's approach for the map step.
195
198
  let reactAssetsHostDir = targetHost;
196
199
  for (const jsUrl of getJsUrls()) {
197
- const jsUrlHost = new URL(jsUrl).host.replace(":", "_");
200
+ const jsUrlHost = new URL(jsUrl).host;
198
201
  if (jsUrlHost !== targetHost) {
199
202
  reactAssetsHostDir = jsUrlHost;
200
203
  break;
@@ -202,21 +205,21 @@ const processUrl = (url_1, outputDir_1, workingDir_1, cmd_1, isBatch_1, ...args_
202
205
  }
203
206
  resetSkipStep();
204
207
  yield Promise.race([
205
- refactor(mappedJsonFileReact, refactorOutputDirReact, detectedBundlerTechReact, false, undefined, undefined, `${outputDir}/${reactAssetsHostDir}/assets`),
208
+ refactor(mappedJsonFileReact, refactorOutputDirReact, detectedBundlerTechReact, false, undefined, undefined, path.join(resolveHostOutputDirectory(outputDir, reactAssetsHostDir, isBatch), "assets")),
206
209
  getSkipStepPromise(),
207
210
  ]);
208
211
  if (shouldSkipTarget())
209
212
  return;
210
- console.log(chalk.bgGreen("[+] Refactor complete."));
213
+ printMsg(MSG.Run, "[+] Refactor complete.");
211
214
  }
212
215
  else {
213
- console.log(chalk.yellow("[!] Bundler not detected via CS-MAST-S, skipping refactor."));
216
+ printMsg(MSG.Warn, "[!] Bundler not detected via CS-MAST-S, skipping refactor.");
214
217
  }
215
218
  }
216
219
  else {
217
- console.log(chalk.yellow("[!] Refactor step disabled via --disable-refactor, skipping."));
220
+ printMsg(MSG.Warn, "[!] Refactor step disabled via --disable-refactor, skipping.");
218
221
  }
219
- console.log(chalk.bgGreenBright(`[+] Analysis complete for ${url}.`));
222
+ printMsg(MSG.Run, `[+] Analysis complete for ${url}.`);
220
223
  return;
221
224
  }
222
225
  if (detectedTech === "vue") {
@@ -230,7 +233,7 @@ const processUrl = (url_1, outputDir_1, workingDir_1, cmd_1, isBatch_1, ...args_
230
233
  const reportDbFile = isBatch ? `${workingDir}/js-recon.db` : "js-recon.db";
231
234
  const reportFile = isBatch ? `${workingDir}/report` : "report";
232
235
  const endpointsFile = isBatch ? `${workingDir}/endpoints` : "endpoints";
233
- console.log(chalk.bgCyan("[2/4] Running map to find functions and API calls..."));
236
+ printMsg(MSG.Header, "[2/4] Running map to find functions and API calls...");
234
237
  globalsUtil.setOpenapi(true);
235
238
  if (isBatch) {
236
239
  globalsUtil.setOpenapiOutputFile(openapiFile);
@@ -245,20 +248,19 @@ const processUrl = (url_1, outputDir_1, workingDir_1, cmd_1, isBatch_1, ...args_
245
248
  map(outputDir, mappedFileVue, ["json"], "vue", false, false, cmd.command || []),
246
249
  getSkipStepPromise(),
247
250
  ]);
248
- console.log(chalk.bgGreen("[+] Map complete."));
251
+ printMsg(MSG.Run, "[+] Map complete.");
249
252
  if (shouldSkipTarget())
250
253
  return;
251
- console.log(chalk.bgCyan("[3/4] Running analyze..."));
254
+ printMsg(MSG.Header, "[3/4] Running analyze...");
252
255
  resetSkipStep();
253
- // @ts-ignore
254
256
  yield Promise.race([
255
- analyze(cmd.rules || "", mappedJsonFileVue, "vue", false, openapiFile, false, analyzeFile, !!cmd.disableRulesVersionCheck),
257
+ analyze(cmd.rules || "", mappedJsonFileVue, "vue", false, openapiFile, false, analyzeFile, !!cmd.disableRulesVersionCheck, false, false),
256
258
  getSkipStepPromise(),
257
259
  ]);
258
- console.log(chalk.bgGreen("[+] Analyze complete."));
260
+ printMsg(MSG.Run, "[+] Analyze complete.");
259
261
  if (shouldSkipTarget())
260
262
  return;
261
- console.log(chalk.bgCyan("[4/4] Running report module..."));
263
+ printMsg(MSG.Header, "[4/4] Running report module...");
262
264
  // Endpoints extraction isn't implemented for Vue yet; pass an empty file if absent.
263
265
  const endpointsJson = `${endpointsFile}.json`;
264
266
  if (!fs.existsSync(endpointsJson)) {
@@ -266,20 +268,20 @@ const processUrl = (url_1, outputDir_1, workingDir_1, cmd_1, isBatch_1, ...args_
266
268
  }
267
269
  resetSkipStep();
268
270
  yield Promise.race([
269
- report(reportDbFile, mappedJsonFileVue, analyzeFile, endpointsJson, openapiFile, reportFile),
271
+ report(reportDbFile, mappedJsonFileVue, analyzeFile, endpointsJson, openapiFile, reportFile, cmd.sj, cmd.sjBin, cmd.sjArgs),
270
272
  getSkipStepPromise(),
271
273
  ]);
272
- console.log(chalk.bgGreen("[+] Report complete."));
274
+ printMsg(MSG.Run, "[+] Report complete.");
273
275
  if (shouldSkipTarget())
274
276
  return;
275
277
  if (!cmd.disableRefactor) {
276
- console.log(chalk.bgCyan("[*] Detecting bundler via CS-MAST-S for refactor..."));
278
+ printMsg(MSG.Header, "[*] Detecting bundler via CS-MAST-S for refactor...");
277
279
  const detectedBundlerTechVue = yield detectBundler(mappedJsonFileVue, "vue", Number((_b = cmd.csMastTechDetectThreshold) !== null && _b !== void 0 ? _b : 50));
278
280
  if (detectedBundlerTechVue) {
279
281
  const refactorOutputDirVue = isBatch ? `${workingDir}/refactored` : "refactored";
280
282
  if (fs.existsSync(refactorOutputDirVue))
281
283
  fs.rmSync(refactorOutputDirVue, { recursive: true });
282
- console.log(chalk.bgCyan(`[*] Running refactor (${detectedBundlerTechVue})...`));
284
+ printMsg(MSG.Header, `[*] Running refactor (${detectedBundlerTechVue})...`);
283
285
  resetSkipStep();
284
286
  yield Promise.race([
285
287
  refactor(mappedJsonFileVue, refactorOutputDirVue, detectedBundlerTechVue, false),
@@ -287,16 +289,16 @@ const processUrl = (url_1, outputDir_1, workingDir_1, cmd_1, isBatch_1, ...args_
287
289
  ]);
288
290
  if (shouldSkipTarget())
289
291
  return;
290
- console.log(chalk.bgGreen("[+] Refactor complete."));
292
+ printMsg(MSG.Run, "[+] Refactor complete.");
291
293
  }
292
294
  else {
293
- console.log(chalk.yellow("[!] Bundler not detected via CS-MAST-S, skipping refactor."));
295
+ printMsg(MSG.Warn, "[!] Bundler not detected via CS-MAST-S, skipping refactor.");
294
296
  }
295
297
  }
296
298
  else {
297
- console.log(chalk.yellow("[!] Refactor step disabled via --disable-refactor, skipping."));
299
+ printMsg(MSG.Warn, "[!] Refactor step disabled via --disable-refactor, skipping.");
298
300
  }
299
- console.log(chalk.bgGreenBright(`[+] Analysis complete for ${url}.`));
301
+ printMsg(MSG.Run, `[+] Analysis complete for ${url}.`);
300
302
  return;
301
303
  }
302
304
  if (detectedTech === "nuxt") {
@@ -308,7 +310,7 @@ const processUrl = (url_1, outputDir_1, workingDir_1, cmd_1, isBatch_1, ...args_
308
310
  const reportDbFile = isBatch ? `${workingDir}/js-recon.db` : "js-recon.db";
309
311
  const reportFile = isBatch ? `${workingDir}/report` : "report";
310
312
  const endpointsFile = isBatch ? `${workingDir}/endpoints` : "endpoints";
311
- console.log(chalk.bgCyan("[2/4] Running map to find functions and API calls..."));
313
+ printMsg(MSG.Header, "[2/4] Running map to find functions and API calls...");
312
314
  globalsUtil.setOpenapi(true);
313
315
  if (isBatch) {
314
316
  globalsUtil.setOpenapiOutputFile(openapiFile);
@@ -323,40 +325,39 @@ const processUrl = (url_1, outputDir_1, workingDir_1, cmd_1, isBatch_1, ...args_
323
325
  map(outputDir, mappedFileNuxt, ["json"], "vue", false, false, cmd.command || []),
324
326
  getSkipStepPromise(),
325
327
  ]);
326
- console.log(chalk.bgGreen("[+] Map complete."));
328
+ printMsg(MSG.Run, "[+] Map complete.");
327
329
  if (shouldSkipTarget())
328
330
  return;
329
- console.log(chalk.bgCyan("[3/4] Running analyze..."));
331
+ printMsg(MSG.Header, "[3/4] Running analyze...");
330
332
  resetSkipStep();
331
- // @ts-ignore
332
333
  yield Promise.race([
333
- analyze(cmd.rules || "", mappedJsonFileNuxt, "vue", false, openapiFile, false, analyzeFile, !!cmd.disableRulesVersionCheck),
334
+ analyze(cmd.rules || "", mappedJsonFileNuxt, "vue", false, openapiFile, false, analyzeFile, !!cmd.disableRulesVersionCheck, false, false),
334
335
  getSkipStepPromise(),
335
336
  ]);
336
- console.log(chalk.bgGreen("[+] Analyze complete."));
337
+ printMsg(MSG.Run, "[+] Analyze complete.");
337
338
  if (shouldSkipTarget())
338
339
  return;
339
- console.log(chalk.bgCyan("[4/4] Running report module..."));
340
+ printMsg(MSG.Header, "[4/4] Running report module...");
340
341
  const endpointsJson = `${endpointsFile}.json`;
341
342
  if (!fs.existsSync(endpointsJson)) {
342
343
  fs.writeFileSync(endpointsJson, "[]");
343
344
  }
344
345
  resetSkipStep();
345
346
  yield Promise.race([
346
- report(reportDbFile, mappedJsonFileNuxt, analyzeFile, endpointsJson, openapiFile, reportFile),
347
+ report(reportDbFile, mappedJsonFileNuxt, analyzeFile, endpointsJson, openapiFile, reportFile, cmd.sj, cmd.sjBin, cmd.sjArgs),
347
348
  getSkipStepPromise(),
348
349
  ]);
349
- console.log(chalk.bgGreen("[+] Report complete."));
350
+ printMsg(MSG.Run, "[+] Report complete.");
350
351
  if (shouldSkipTarget())
351
352
  return;
352
353
  if (!cmd.disableRefactor) {
353
- console.log(chalk.bgCyan("[*] Detecting bundler via CS-MAST-S for refactor..."));
354
+ printMsg(MSG.Header, "[*] Detecting bundler via CS-MAST-S for refactor...");
354
355
  const detectedBundlerTechNuxt = yield detectBundler(mappedJsonFileNuxt, "nuxt", Number((_c = cmd.csMastTechDetectThreshold) !== null && _c !== void 0 ? _c : 50));
355
356
  if (detectedBundlerTechNuxt) {
356
357
  const refactorOutputDirNuxt = isBatch ? `${workingDir}/refactored` : "refactored";
357
358
  if (fs.existsSync(refactorOutputDirNuxt))
358
359
  fs.rmSync(refactorOutputDirNuxt, { recursive: true });
359
- console.log(chalk.bgCyan(`[*] Running refactor (${detectedBundlerTechNuxt})...`));
360
+ printMsg(MSG.Header, `[*] Running refactor (${detectedBundlerTechNuxt})...`);
360
361
  resetSkipStep();
361
362
  yield Promise.race([
362
363
  refactor(mappedJsonFileNuxt, refactorOutputDirNuxt, detectedBundlerTechNuxt, false),
@@ -364,16 +365,16 @@ const processUrl = (url_1, outputDir_1, workingDir_1, cmd_1, isBatch_1, ...args_
364
365
  ]);
365
366
  if (shouldSkipTarget())
366
367
  return;
367
- console.log(chalk.bgGreen("[+] Refactor complete."));
368
+ printMsg(MSG.Run, "[+] Refactor complete.");
368
369
  }
369
370
  else {
370
- console.log(chalk.yellow("[!] Bundler not detected via CS-MAST-S, skipping refactor."));
371
+ printMsg(MSG.Warn, "[!] Bundler not detected via CS-MAST-S, skipping refactor.");
371
372
  }
372
373
  }
373
374
  else {
374
- console.log(chalk.yellow("[!] Refactor step disabled via --disable-refactor, skipping."));
375
+ printMsg(MSG.Warn, "[!] Refactor step disabled via --disable-refactor, skipping.");
375
376
  }
376
- console.log(chalk.bgGreenBright(`[+] Analysis complete for ${url}.`));
377
+ printMsg(MSG.Run, `[+] Analysis complete for ${url}.`);
377
378
  return;
378
379
  }
379
380
  if (detectedTech === "svelte") {
@@ -384,7 +385,7 @@ const processUrl = (url_1, outputDir_1, workingDir_1, cmd_1, isBatch_1, ...args_
384
385
  const reportDbFile = isBatch ? `${workingDir}/js-recon.db` : "js-recon.db";
385
386
  const reportFile = isBatch ? `${workingDir}/report` : "report";
386
387
  const endpointsFile = isBatch ? `${workingDir}/endpoints` : "endpoints";
387
- console.log(chalk.bgCyan("[2/4] Running map to find functions and API calls..."));
388
+ printMsg(MSG.Header, "[2/4] Running map to find functions and API calls...");
388
389
  globalsUtil.setOpenapi(true);
389
390
  if (isBatch) {
390
391
  globalsUtil.setOpenapiOutputFile(openapiFile);
@@ -399,31 +400,30 @@ const processUrl = (url_1, outputDir_1, workingDir_1, cmd_1, isBatch_1, ...args_
399
400
  map(outputDir, mappedFileSvelte, ["json"], "svelte", false, false, cmd.command || []),
400
401
  getSkipStepPromise(),
401
402
  ]);
402
- console.log(chalk.bgGreen("[+] Map complete."));
403
+ printMsg(MSG.Run, "[+] Map complete.");
403
404
  if (shouldSkipTarget())
404
405
  return;
405
- console.log(chalk.bgCyan("[3/4] Running analyze..."));
406
+ printMsg(MSG.Header, "[3/4] Running analyze...");
406
407
  resetSkipStep();
407
- // @ts-ignore
408
408
  yield Promise.race([
409
- analyze(cmd.rules || "", mappedJsonFileSvelte, "svelte", false, openapiFile, false, analyzeFile, !!cmd.disableRulesVersionCheck),
409
+ analyze(cmd.rules || "", mappedJsonFileSvelte, "svelte", false, openapiFile, false, analyzeFile, !!cmd.disableRulesVersionCheck, false, false),
410
410
  getSkipStepPromise(),
411
411
  ]);
412
- console.log(chalk.bgGreen("[+] Analyze complete."));
412
+ printMsg(MSG.Run, "[+] Analyze complete.");
413
413
  if (shouldSkipTarget())
414
414
  return;
415
- console.log(chalk.bgCyan("[4/4] Running report module..."));
415
+ printMsg(MSG.Header, "[4/4] Running report module...");
416
416
  const endpointsJson = `${endpointsFile}.json`;
417
417
  if (!fs.existsSync(endpointsJson)) {
418
418
  fs.writeFileSync(endpointsJson, "[]");
419
419
  }
420
420
  resetSkipStep();
421
421
  yield Promise.race([
422
- report(reportDbFile, mappedJsonFileSvelte, analyzeFile, endpointsJson, openapiFile, reportFile),
422
+ report(reportDbFile, mappedJsonFileSvelte, analyzeFile, endpointsJson, openapiFile, reportFile, cmd.sj, cmd.sjBin, cmd.sjArgs),
423
423
  getSkipStepPromise(),
424
424
  ]);
425
- console.log(chalk.bgGreen("[+] Report complete."));
426
- console.log(chalk.bgGreenBright(`[+] Analysis complete for ${url}.`));
425
+ printMsg(MSG.Run, "[+] Report complete.");
426
+ printMsg(MSG.Run, `[+] Analysis complete for ${url}.`);
427
427
  return;
428
428
  }
429
429
  if (detectedTech === "angular") {
@@ -437,8 +437,8 @@ const processUrl = (url_1, outputDir_1, workingDir_1, cmd_1, isBatch_1, ...args_
437
437
  const reportDbFile = isBatch ? `${workingDir}/js-recon.db` : "js-recon.db";
438
438
  const reportFile = isBatch ? `${workingDir}/report` : "report";
439
439
  const endpointsFile = isBatch ? `${workingDir}/endpoints` : "endpoints";
440
- const angularHostDir = `${outputDir}/${targetHost}`;
441
- console.log(chalk.bgCyan("[2/4] Running map to find functions and API calls..."));
440
+ const angularHostDir = resolveHostOutputDirectory(outputDir, targetHost, isBatch);
441
+ printMsg(MSG.Header, "[2/4] Running map to find functions and API calls...");
442
442
  globalsUtil.setOpenapi(true);
443
443
  if (isBatch) {
444
444
  globalsUtil.setOpenapiOutputFile(openapiFile);
@@ -453,31 +453,30 @@ const processUrl = (url_1, outputDir_1, workingDir_1, cmd_1, isBatch_1, ...args_
453
453
  map(angularHostDir, mappedFileAngular, ["json"], "angular", false, false, cmd.command || []),
454
454
  getSkipStepPromise(),
455
455
  ]);
456
- console.log(chalk.bgGreen("[+] Map complete."));
456
+ printMsg(MSG.Run, "[+] Map complete.");
457
457
  if (shouldSkipTarget())
458
458
  return;
459
- console.log(chalk.bgCyan("[3/4] Running analyze..."));
459
+ printMsg(MSG.Header, "[3/4] Running analyze...");
460
460
  resetSkipStep();
461
- // @ts-ignore
462
461
  yield Promise.race([
463
- analyze(cmd.rules || "", mappedJsonFileAngular, "angular", false, openapiFile, false, analyzeFile, !!cmd.disableRulesVersionCheck),
462
+ analyze(cmd.rules || "", mappedJsonFileAngular, "angular", false, openapiFile, false, analyzeFile, !!cmd.disableRulesVersionCheck, false, false),
464
463
  getSkipStepPromise(),
465
464
  ]);
466
- console.log(chalk.bgGreen("[+] Analyze complete."));
465
+ printMsg(MSG.Run, "[+] Analyze complete.");
467
466
  if (shouldSkipTarget())
468
467
  return;
469
- console.log(chalk.bgCyan("[4/4] Running report module..."));
468
+ printMsg(MSG.Header, "[4/4] Running report module...");
470
469
  const endpointsJson = `${endpointsFile}.json`;
471
470
  if (!fs.existsSync(endpointsJson)) {
472
471
  fs.writeFileSync(endpointsJson, "[]");
473
472
  }
474
473
  resetSkipStep();
475
474
  yield Promise.race([
476
- report(reportDbFile, mappedJsonFileAngular, analyzeFile, endpointsJson, openapiFile, reportFile),
475
+ report(reportDbFile, mappedJsonFileAngular, analyzeFile, endpointsJson, openapiFile, reportFile, cmd.sj, cmd.sjBin, cmd.sjArgs),
477
476
  getSkipStepPromise(),
478
477
  ]);
479
- console.log(chalk.bgGreen("[+] Report complete."));
480
- console.log(chalk.bgGreenBright(`[+] Analysis complete for ${url}.`));
478
+ printMsg(MSG.Run, "[+] Report complete.");
479
+ printMsg(MSG.Run, `[+] Analysis complete for ${url}.`);
481
480
  return;
482
481
  }
483
482
  const stringsFile = isBatch ? `${workingDir}/strings.json` : "strings.json";
@@ -492,58 +491,52 @@ const processUrl = (url_1, outputDir_1, workingDir_1, cmd_1, isBatch_1, ...args_
492
491
  // if the target is using a CDN, then just passing the outputDir/host won't work, and would throw an error.
493
492
  // So, if the target was found to be using a CDN, scan the CDN directory rather than the outputDir/host
494
493
  // One IMPORTANT thing: this is only meant for modules that rely on just the code (map)
495
- const cdnDir = yield getCdnDir(url, outputDir);
496
- const cdnOutputDir = cdnDir ? cdnDir : outputDir + "/" + targetHost;
497
- console.log(chalk.bgCyan("[2/8] Running strings to extract endpoints..."));
494
+ const cdnDir = yield getCdnDir(url, outputDir, isBatch);
495
+ const cdnOutputDir = cdnDir ? cdnDir : resolveHostOutputDirectory(outputDir, targetHost, isBatch);
496
+ printMsg(MSG.Header, "[2/8] Running strings to extract endpoints...");
498
497
  resetSkipStep();
499
498
  yield Promise.race([
500
499
  strings(outputDir, stringsFile, true, extractedUrlsFile, false, false, false, false),
501
500
  getSkipStepPromise(),
502
501
  ]);
503
- console.log(chalk.bgGreen("[+] Strings complete."));
502
+ printMsg(MSG.Run, "[+] Strings complete.");
504
503
  if (shouldSkipTarget())
505
504
  return;
506
- console.log(chalk.bgCyan("[3/8] Running lazyload with subsequent requests to download JavaScript files..."));
505
+ printMsg(MSG.Header, "[3/8] Running lazyload with subsequent requests to download JavaScript files...");
507
506
  resetSkipStep();
508
- yield Promise.race([
509
- lazyLoad(url, outputDir, cmd.strictScope, cmd.scope.split(","), cmd.threads, true, `${extractedUrlsFile}.json`, cmd.insecure, true, cmd.sourcemapDir, cmd.research, cmd.researchOutput, Number(cmd.maxIterations), Number(cmd.maxJsSize), Number(cmd.lazyloadTimeout) * 60 * 1000, Number(cmd.maxPages), includeMethods, excludeMethods, Number(cmd.detectionTimeout) * 1000),
510
- getSkipStepPromise(),
511
- ]);
512
- console.log(chalk.bgGreen("[+] Lazyload with subsequent requests complete."));
507
+ yield awaitCancellableStep((signal) => lazyLoad(url, outputDir, cmd.strictScope, cmd.scope.split(","), cmd.threads, true, `${extractedUrlsFile}.json`, cmd.insecure, true, cmd.sourcemapDir, cmd.research, cmd.researchOutput, Number(cmd.maxIterations), Number(cmd.maxJsSize), Number(cmd.lazyloadTimeout) * 60 * 1000, Number(cmd.maxPages), includeMethods, excludeMethods, Number(cmd.detectionTimeout) * 1000, signal, isBatch, Number(cmd.maxRedirects), cmd.strings, Number(cmd.stringsMaxIterations), Number(cmd.stagnationTimein) * 60 * 1000, Number(cmd.stagnationPercentage), Number(cmd.stagnationMonitor) * 60 * 1000, Number(cmd.rscParamBruteforceLimit)), getSkipStepPromise());
508
+ printMsg(MSG.Run, "[+] Lazyload with subsequent requests complete.");
513
509
  if (shouldSkipTarget())
514
510
  return;
515
- console.log(chalk.bgCyan("[4/8] Running strings again to extract endpoints..."));
511
+ printMsg(MSG.Header, "[4/8] Running strings again to extract endpoints...");
516
512
  resetSkipStep();
517
513
  yield Promise.race([
518
- strings(outputDir, stringsFile, true, extractedUrlsFile, cmd.secrets, true, true, cmd.trufflehog),
514
+ strings(outputDir, stringsFile, true, extractedUrlsFile, cmd.secrets, true, true, cmd.trufflehog, cmd.trufflehogBin, cmd.trufflehogAcceptTerms),
519
515
  getSkipStepPromise(),
520
516
  ]);
521
- console.log(chalk.bgGreen("[+] Strings complete."));
517
+ printMsg(MSG.Run, "[+] Strings complete.");
522
518
  if (shouldSkipTarget())
523
519
  return;
524
520
  // a second subsequent_requests pass: the first strings pass only sees initial chunks,
525
521
  // so dynamic routes such as `/post/1` are only discovered after the first subsequent
526
522
  // crawl + second strings extraction. Re-running subsequent_requests with the freshly
527
523
  // updated paths picks up chunks for those dynamic routes (e.g. the post page).
528
- console.log(chalk.bgCyan("[4.5/8] Re-running lazyload with subsequent requests for newly discovered paths..."));
524
+ printMsg(MSG.Header, "[4.5/8] Re-running lazyload with subsequent requests for newly discovered paths...");
529
525
  resetSkipStep();
530
- yield Promise.race([
531
- lazyLoad(url, outputDir, cmd.strictScope, cmd.scope.split(","), cmd.threads, true, `${extractedUrlsFile}.json`, cmd.insecure, false, cmd.sourcemapDir, cmd.research, cmd.researchOutput, Number(cmd.maxIterations), Number(cmd.maxJsSize), Number(cmd.lazyloadTimeout) * 60 * 1000, Number(cmd.maxPages), includeMethods, excludeMethods, Number(cmd.detectionTimeout) * 1000),
532
- getSkipStepPromise(),
533
- ]);
534
- console.log(chalk.bgGreen("[+] Lazyload re-pass complete."));
526
+ yield awaitCancellableStep((signal) => lazyLoad(url, outputDir, cmd.strictScope, cmd.scope.split(","), cmd.threads, true, `${extractedUrlsFile}.json`, cmd.insecure, false, cmd.sourcemapDir, cmd.research, cmd.researchOutput, Number(cmd.maxIterations), Number(cmd.maxJsSize), Number(cmd.lazyloadTimeout) * 60 * 1000, Number(cmd.maxPages), includeMethods, excludeMethods, Number(cmd.detectionTimeout) * 1000, signal, isBatch, Number(cmd.maxRedirects), cmd.strings, Number(cmd.stringsMaxIterations), Number(cmd.stagnationTimein) * 60 * 1000, Number(cmd.stagnationPercentage), Number(cmd.stagnationMonitor) * 60 * 1000, Number(cmd.rscParamBruteforceLimit)), getSkipStepPromise());
527
+ printMsg(MSG.Run, "[+] Lazyload re-pass complete.");
535
528
  if (shouldSkipTarget())
536
529
  return;
537
- console.log(chalk.bgCyan("[4.6/8] Re-running strings for chunks from the re-pass..."));
530
+ printMsg(MSG.Header, "[4.6/8] Re-running strings for chunks from the re-pass...");
538
531
  resetSkipStep();
539
532
  yield Promise.race([
540
- strings(outputDir, stringsFile, true, extractedUrlsFile, cmd.secrets, true, true, cmd.trufflehog),
533
+ strings(outputDir, stringsFile, true, extractedUrlsFile, cmd.secrets, true, true, cmd.trufflehog, cmd.trufflehogBin, cmd.trufflehogAcceptTerms),
541
534
  getSkipStepPromise(),
542
535
  ]);
543
- console.log(chalk.bgGreen("[+] Strings re-pass complete."));
536
+ printMsg(MSG.Run, "[+] Strings re-pass complete.");
544
537
  if (shouldSkipTarget())
545
538
  return;
546
- console.log(chalk.bgCyan("[5/8] Running map to find functions..."));
539
+ printMsg(MSG.Header, "[5/8] Running map to find functions...");
547
540
  globalsUtil.setOpenapi(true);
548
541
  if (isBatch) {
549
542
  globalsUtil.setOpenapiOutputFile(openapiFile);
@@ -561,14 +554,15 @@ const processUrl = (url_1, outputDir_1, workingDir_1, cmd_1, isBatch_1, ...args_
561
554
  map(cdnOutputDir, mappedFile, ["json"], detectedTech, false, false, cmd.command || []),
562
555
  getSkipStepPromise(),
563
556
  ]);
564
- console.log(chalk.bgGreen("[+] Map complete."));
557
+ printMsg(MSG.Run, "[+] Map complete.");
565
558
  if (shouldSkipTarget())
566
559
  return;
567
- console.log(chalk.bgCyan("[6/8] Running endpoints to extract endpoints..."));
560
+ printMsg(MSG.Header, "[6/8] Running endpoints to extract endpoints...");
568
561
  resetSkipStep();
569
- if (fs.existsSync(`${outputDir}/${targetHost}/___subsequent_requests`)) {
562
+ const targetOutputDir = resolveHostOutputDirectory(outputDir, targetHost, isBatch);
563
+ if (fs.existsSync(path.join(targetOutputDir, "___subsequent_requests"))) {
570
564
  yield Promise.race([
571
- endpoints(url, `${outputDir}/${targetHost}/`, endpointsFile, ["json"], "next", false, mappedJsonFile),
565
+ endpoints(url, targetOutputDir, endpointsFile, ["json"], "next", false, mappedJsonFile),
572
566
  getSkipStepPromise(),
573
567
  ]);
574
568
  }
@@ -578,35 +572,35 @@ const processUrl = (url_1, outputDir_1, workingDir_1, cmd_1, isBatch_1, ...args_
578
572
  getSkipStepPromise(),
579
573
  ]);
580
574
  }
581
- console.log(chalk.bgGreen("[+] Endpoints complete."));
575
+ printMsg(MSG.Run, "[+] Endpoints complete.");
582
576
  if (shouldSkipTarget())
583
577
  return;
584
- console.log(chalk.bgCyan("[7/8] Running analyze to extract endpoints..."));
578
+ printMsg(MSG.Header, "[7/8] Running analyze to extract endpoints...");
585
579
  resetSkipStep();
586
580
  yield Promise.race([
587
- analyze(cmd.rules || "", mappedJsonFile, detectedTech, false, openapiFile, false, analyzeFile, !!cmd.disableRulesVersionCheck),
581
+ analyze(cmd.rules || "", mappedJsonFile, detectedTech, false, openapiFile, false, analyzeFile, !!cmd.disableRulesVersionCheck, false, false),
588
582
  getSkipStepPromise(),
589
583
  ]);
590
- console.log(chalk.bgGreen("[+] Analyze complete."));
584
+ printMsg(MSG.Run, "[+] Analyze complete.");
591
585
  if (shouldSkipTarget())
592
586
  return;
593
- console.log(chalk.bgCyan("[8/8] Running report module..."));
587
+ printMsg(MSG.Header, "[8/8] Running report module...");
594
588
  resetSkipStep();
595
589
  yield Promise.race([
596
- report(reportDbFile, mappedJsonFile, analyzeFile, `${endpointsFile}.json`, openapiFile, reportFile),
590
+ report(reportDbFile, mappedJsonFile, analyzeFile, `${endpointsFile}.json`, openapiFile, reportFile, cmd.sj, cmd.sjBin, cmd.sjArgs),
597
591
  getSkipStepPromise(),
598
592
  ]);
599
- console.log(chalk.bgGreen("[+] Report complete."));
593
+ printMsg(MSG.Run, "[+] Report complete.");
600
594
  if (shouldSkipTarget())
601
595
  return;
602
596
  if (!cmd.disableRefactor) {
603
- console.log(chalk.bgCyan("[*] Detecting bundler via CS-MAST-S for refactor..."));
597
+ printMsg(MSG.Header, "[*] Detecting bundler via CS-MAST-S for refactor...");
604
598
  const detectedBundlerTechNext = yield detectBundler(mappedJsonFile, detectedTech, Number((_d = cmd.csMastTechDetectThreshold) !== null && _d !== void 0 ? _d : 50));
605
599
  if (detectedBundlerTechNext) {
606
600
  const refactorOutputDirNext = isBatch ? `${workingDir}/refactored` : "refactored";
607
601
  if (fs.existsSync(refactorOutputDirNext))
608
602
  fs.rmSync(refactorOutputDirNext, { recursive: true });
609
- console.log(chalk.bgCyan(`[*] Running refactor (${detectedBundlerTechNext})...`));
603
+ printMsg(MSG.Header, `[*] Running refactor (${detectedBundlerTechNext})...`);
610
604
  resetSkipStep();
611
605
  yield Promise.race([
612
606
  refactor(mappedJsonFile, refactorOutputDirNext, detectedBundlerTechNext, false),
@@ -614,29 +608,17 @@ const processUrl = (url_1, outputDir_1, workingDir_1, cmd_1, isBatch_1, ...args_
614
608
  ]);
615
609
  if (shouldSkipTarget())
616
610
  return;
617
- console.log(chalk.bgGreen("[+] Refactor complete."));
611
+ printMsg(MSG.Run, "[+] Refactor complete.");
618
612
  }
619
613
  else {
620
- console.log(chalk.yellow("[!] Bundler not detected via CS-MAST-S, skipping refactor."));
614
+ printMsg(MSG.Warn, "[!] Bundler not detected via CS-MAST-S, skipping refactor.");
621
615
  }
622
616
  }
623
617
  else {
624
- console.log(chalk.yellow("[!] Refactor step disabled via --disable-refactor, skipping."));
618
+ printMsg(MSG.Warn, "[!] Refactor step disabled via --disable-refactor, skipping.");
625
619
  }
626
- console.log(chalk.bgGreenBright(`[+] Analysis complete for ${url}.`));
620
+ printMsg(MSG.Run, `[+] Analysis complete for ${url}.`);
627
621
  });
628
- /**
629
- * Removes everything inside a directory without removing the directory itself.
630
- *
631
- * Used instead of `fs.rmSync(dir, { recursive: true })` for --output-overwrite: the output
632
- * directory may be a Docker bind-mount point, and removing a mount point throws EBUSY
633
- * ("Device or resource busy") even from inside the container's own mount namespace.
634
- */
635
- const emptyDir = (dir) => {
636
- for (const entry of fs.readdirSync(dir)) {
637
- fs.rmSync(path.join(dir, entry), { recursive: true, force: true });
638
- }
639
- };
640
622
  /**
641
623
  * Main handler for the 'run' command that executes the complete js-recon analysis pipeline.
642
624
  *
@@ -647,109 +629,162 @@ const emptyDir = (dir) => {
647
629
  * @param cmd - The command-line options object from commander.js
648
630
  * @returns Promise that resolves when all URL processing is complete
649
631
  */
632
+ /**
633
+ * Parses a batch/single `cmd.url` into the `{ url, hostDir, dir }` entries the
634
+ * dashboard state store needs, mirroring the hostDir/dir resolution the batch
635
+ * loop and single-target path use below. Invalid URLs are dropped — they're
636
+ * reported (and skipped) by the existing validation further down.
637
+ */
638
+ const buildDashboardTargetEntries = (cmd, isBatch) => {
639
+ const toEntry = (url, dir) => {
640
+ try {
641
+ return { url, hostDir: new URL(url).host.replace(":", "_"), dir };
642
+ }
643
+ catch (_a) {
644
+ return null;
645
+ }
646
+ };
647
+ if (!isBatch) {
648
+ const entry = toEntry(cmd.url, cmd.output);
649
+ return entry ? [entry] : [];
650
+ }
651
+ return fs
652
+ .readFileSync(cmd.url, "utf-8")
653
+ .split("\n")
654
+ .filter((url) => url !== "")
655
+ .map((url) => toEntry(url, `${cmd.output}/${new URL(url).host.replace(":", "_")}`))
656
+ .filter((e) => e !== null);
657
+ };
650
658
  export default (cmd) => __awaiter(void 0, void 0, void 0, function* () {
651
- var _a, _b, _c, _d, _e;
659
+ var _a, _b, _c, _d, _e, _f;
660
+ const resolvedTargets = resolveTargetInputs(cmd.url);
652
661
  configureProxy(cmd);
662
+ if (getOxylabsFallbackConfiguration().enabled)
663
+ globalsUtil.setUseProxy(false);
653
664
  // Snapshot the originally-configured proxy state so `processUrl`'s --proxy-waf-fallback check
654
665
  // can reset it before each target in batch mode, regardless of what a previous target left it as.
655
- cmd._proxyConfigured = globalsUtil.getUseProxy();
656
666
  globalsUtil.setDisableCache(cmd.disableCache);
657
667
  globalsUtil.setRespCacheFile(cmd.cacheFile);
658
668
  globalsUtil.setYes(cmd.yes);
659
- const isBatch = fs.existsSync(cmd.url);
669
+ const outputOverwrite = cmd.outputOverwrite === true;
670
+ const outputReservation = reserveRunOutputDirectory(cmd.output, outputOverwrite);
671
+ const isBatch = resolvedTargets.isBatch;
672
+ const runCommand = Object.freeze(Object.assign(Object.assign({}, cmd), { output: outputReservation.path, _proxyConfigured: globalsUtil.getUseProxy() }));
673
+ if (outputReservation.redirected) {
674
+ console.log(chalk.yellow(`[i] Output directory ${cmd.output} is already occupied; using ${outputReservation.path} instead.`));
675
+ }
676
+ if (outputOverwrite && outputReservation.occupied) {
677
+ console.log(chalk.yellow(`[!] Output directory ${runCommand.output} already exists. Overwriting it.`));
678
+ clearRunOutputDirectory(runCommand.output);
679
+ }
660
680
  installSigintHandler(isBatch);
661
- const outputOverwrite = cmd.outputOverwrite || process.env.JS_RECON_OUTPUT_OVERWRITE === "true";
681
+ let dashboard = null;
682
+ if (cmd.webStatsDashboard) {
683
+ dashboardState.registerTargets(buildDashboardTargetEntries(cmd, isBatch));
684
+ dashboard = yield startDashboardServer(Number(cmd.webStatsPort));
685
+ printMsg(MSG.Run, `[+] Web stats dashboard running at ${dashboard.url}`);
686
+ setHeaderListener((msg) => dashboardState.markStep(msg));
687
+ }
662
688
  try {
663
- // check if the given URL is a file
664
689
  if (!isBatch) {
665
- // check if output directory exists. If so, ask the user to switch to other directory
666
- // if not done, it might conflict this process
667
- // for devs: run `npm run cleanup` to prepare this directory
668
- if (fs.existsSync(cmd.output)) {
669
- if (outputOverwrite) {
670
- console.log(chalk.yellow(`[!] Output directory ${cmd.output} already exists. Overwriting it.`));
671
- emptyDir(cmd.output);
672
- }
673
- else {
674
- console.error(chalk.red(`[!] Output directory ${cmd.output} already exists. Please switch to other directory or it might conflict with this process.`));
675
- console.log(chalk.yellow(`[i] For advanced users: use the individual modules separately. See docs at ${CONFIG.modulesDocs}`));
676
- process.exit(11);
677
- }
690
+ if (cmd.webStatsDashboard) {
691
+ dashboardState.setCurrentUrl(resolvedTargets.targets[0]);
692
+ dashboardState.markRunning(resolvedTargets.targets[0]);
678
693
  }
679
694
  try {
680
- new URL(cmd.url);
695
+ yield processUrl(resolvedTargets.targets[0], runCommand.output, ".", runCommand, false, (_a = runCommand._includeMethods) !== null && _a !== void 0 ? _a : [], (_b = runCommand._excludeMethods) !== null && _b !== void 0 ? _b : []);
696
+ if (cmd.webStatsDashboard)
697
+ dashboardState.markCompleted(resolvedTargets.targets[0]);
681
698
  }
682
699
  catch (e) {
683
- console.error(chalk.red(`[!] Invalid URL: ${cmd.url}`));
684
- process.exit(12);
700
+ if (cmd.webStatsDashboard)
701
+ dashboardState.markError(resolvedTargets.targets[0], e instanceof Error ? e.message : String(e));
702
+ throw e;
685
703
  }
686
- yield processUrl(cmd.url, cmd.output, ".", cmd, false, (_a = cmd._includeMethods) !== null && _a !== void 0 ? _a : [], (_b = cmd._excludeMethods) !== null && _b !== void 0 ? _b : []);
687
704
  }
688
705
  else {
689
- // since this is a file, we need to first load the URLs in the memory remove empty strings
690
- const urls = fs
691
- .readFileSync(cmd.url, "utf-8")
692
- .split("\n")
693
- .filter((url) => url !== "");
694
- if (!fs.existsSync(cmd.output)) {
695
- fs.mkdirSync(cmd.output, { recursive: true });
696
- }
697
- const globalDbPath = `${cmd.output}/js-recon.db`;
706
+ const globalDbPath = `${runCommand.output}/js-recon.db`;
698
707
  yield initGlobalReportDb(globalDbPath);
699
- for (const url of urls) {
708
+ const targetHosts = resolvedTargets.targets.map((target) => new URL(target).host);
709
+ const hostFrequencies = targetHosts.reduce((frequencies, host) => { var _a; return new Map(frequencies).set(host, ((_a = frequencies.get(host)) !== null && _a !== void 0 ? _a : 0) + 1); }, new Map());
710
+ for (const url of resolvedTargets.targets) {
700
711
  resetSkipTarget();
701
- // Validate URL only
702
- let urlObj;
703
- try {
704
- urlObj = new URL(url);
705
- }
706
- catch (_f) {
707
- console.error(chalk.bgRed(`[!] Invalid URL: ${url}`));
708
- continue;
709
- }
710
- const hostDir = urlObj.host.replace(":", "_");
711
- const thisTargetDir = `${cmd.output}/${hostDir}`;
712
- if (fs.existsSync(thisTargetDir) && outputOverwrite) {
712
+ const urlObj = new URL(url);
713
+ let hostDir = getBatchTargetDirectoryName(url, ((_c = hostFrequencies.get(urlObj.host)) !== null && _c !== void 0 ? _c : 0) > 1);
714
+ const requestedTargetDir = path.join(runCommand.output, hostDir);
715
+ const targetReservation = reserveRunOutputDirectory(requestedTargetDir, outputOverwrite);
716
+ const thisTargetDir = targetReservation.path;
717
+ hostDir = path.basename(thisTargetDir);
718
+ if (outputOverwrite && targetReservation.occupied) {
713
719
  console.log(chalk.yellow(`[!] Output directory ${thisTargetDir} already exists. Overwriting it.`));
714
- emptyDir(thisTargetDir);
720
+ clearRunOutputDirectory(thisTargetDir);
715
721
  }
716
- else if (fs.existsSync(thisTargetDir)) {
717
- console.error(chalk.red(`[!] Output directory ${thisTargetDir} already exists. Skipping ${url}.`));
718
- console.log(chalk.yellow(`[i] For advanced users: use the individual modules separately. See docs at ${CONFIG.modulesDocs}`));
719
- continue;
722
+ else if (targetReservation.redirected) {
723
+ console.log(chalk.yellow(`[i] Target output already exists; using ${thisTargetDir} for ${url}.`));
720
724
  }
721
- fs.mkdirSync(thisTargetDir, { recursive: true });
722
- try {
723
- yield processUrl(url, thisTargetDir, thisTargetDir, cmd, true, (_c = cmd._includeMethods) !== null && _c !== void 0 ? _c : [], (_d = cmd._excludeMethods) !== null && _d !== void 0 ? _d : []);
724
- }
725
- catch (error) {
726
- console.error(chalk.bgRed(`[!] Unhandled error while processing ${url}: ${error}`));
727
- process.exitCode = 1;
725
+ if (cmd.webStatsDashboard && dashboardState.isSkipRequested(url)) {
726
+ printMsg(MSG.Warn, `[!] Skipping ${url} (skipped from the web dashboard).`);
727
+ dashboardState.markSkipped(url);
728
+ targetReservation.release();
728
729
  continue;
729
730
  }
730
- const domainDbPath = `${thisTargetDir}/js-recon.db`;
731
- if (fs.existsSync(domainDbPath)) {
731
+ if (cmd.webStatsDashboard) {
732
+ dashboardState.setCurrentUrl(url);
733
+ dashboardState.markRunning(url);
734
+ }
735
+ try {
732
736
  try {
733
- mergeDomainIntoGlobalDb(globalDbPath, domainDbPath, hostDir);
737
+ yield processUrl(url, thisTargetDir, thisTargetDir, runCommand, true, (_d = runCommand._includeMethods) !== null && _d !== void 0 ? _d : [], (_e = runCommand._excludeMethods) !== null && _e !== void 0 ? _e : []);
738
+ if (cmd.webStatsDashboard) {
739
+ if (shouldSkipTarget())
740
+ dashboardState.markSkipped(url);
741
+ else
742
+ dashboardState.markCompleted(url);
743
+ }
734
744
  }
735
745
  catch (error) {
736
- console.error(chalk.yellow(`[!] Failed to merge ${hostDir} into the global js-recon.db: ${error}`));
746
+ if (cmd.webStatsDashboard)
747
+ dashboardState.markError(url, error instanceof Error ? error.message : String(error));
748
+ printMsg(MSG.Err, `[!] Unhandled error while processing ${url}: ${error}`);
749
+ process.exitCode = 1;
750
+ continue;
751
+ }
752
+ const domainDbPath = `${thisTargetDir}/js-recon.db`;
753
+ if (fs.existsSync(domainDbPath)) {
754
+ try {
755
+ mergeDomainIntoGlobalDb(globalDbPath, domainDbPath, hostDir);
756
+ }
757
+ catch (error) {
758
+ printMsg(MSG.Warn, `[!] Failed to merge ${hostDir} into the global js-recon.db: ${error}`);
759
+ }
760
+ }
761
+ else {
762
+ printMsg(MSG.Warn, `[i] No js-recon.db found for ${hostDir}, skipping merge into the global database.`);
737
763
  }
738
764
  }
739
- else {
740
- console.log(chalk.yellow(`[i] No js-recon.db found for ${hostDir}, skipping merge into the global database.`));
765
+ finally {
766
+ targetReservation.release();
741
767
  }
742
768
  }
743
769
  }
744
770
  }
745
771
  catch (error) {
746
- console.error(chalk.bgRed(`[!] Unhandled error: ${error}`));
772
+ printMsg(MSG.Err, `[!] Unhandled error: ${error}`);
747
773
  process.exitCode = 1;
748
774
  }
749
775
  finally {
750
- yield waitForPendingInterrupt();
751
- removeSigintHandler();
752
- process.exit((_e = process.exitCode) !== null && _e !== void 0 ? _e : 0);
776
+ if (dashboard) {
777
+ setHeaderListener(null);
778
+ yield dashboard.stop();
779
+ }
780
+ try {
781
+ yield waitForPendingInterrupt();
782
+ }
783
+ finally {
784
+ removeSigintHandler();
785
+ outputReservation.release();
786
+ }
787
+ process.exit((_f = process.exitCode) !== null && _f !== void 0 ? _f : 0);
753
788
  }
754
789
  });
755
790
  //# sourceMappingURL=index.js.map