---
# System prepended metadata

title: JS Fetcher
tags: [Squad Of Hunters]

---

# JS Fetcher

`JSFetcher` is a Python-based tool designed to fetch, save, and analyze JavaScript files from a list of provided URLs. It supports features such as proxy usage, custom headers, URL extraction, JavaScript beautification, and optional retrieval of source maps.

## Features

:::success

- **JavaScript Beautification**: Beautify fetched JavaScript files for easier analysis.
- **URL Extraction**: Extract additional `.js` or `.chunk.js` URLs from fetched content and process them recursively.
- **Source Map Retrieval**: Optionally fetch mapping files (`.js.map` and `.map`) referenced in JavaScript files and by adding .map to the end of JavaScript filename.
- **Output Directory**: Save fetched content to a specified directory, preserving the directory structure.
- **Multithreading**: Fetch multiple URLs concurrently using a specified number of threads.
- **Custom Headers**: Add custom headers to requests for authentication or other purposes.
- **Proxy Support**: Use a proxy for requests with validation checks.
- **Retry Mechanism**: Retry failed requests with an exponential backoff.

:::

## Requirements

- Python 3.7+

## Download

The latest version of `JS Fetcher` can be downloaded at the following URL:

```bash
wget https://static.k0.lc/share/js_fetcher.py
```

## Installation & run

The following libraries are required for this project:

```bash
pip3 install docopt jsbeautifier coloredlogs verboselogs tldextract==3.2.0
python3 js_fetcher.py -h
```

## Usage

```html
Usage:
  js_fetcher.py [--scope <scope>] [--mapping-search] [--outdir <directory>] [--proxy <proxy>] [(-H <header>)...]
                [--retry <num_retries>] [--threads <num_threads>] [--timeout <seconds>] [--follow-redirect]
                [--only-request-js-files] [--only-save-js-files | --only-save-orig-js-files] [--no-save-embedded-js]
                [--response-min-size <size>] [--disable-js-beautify] [--disable-js-embedded] [--disable-url-search]
                [--disable-proxy-check] [--disable-recursion] [--disable-cpath-filter] [--headers-from-file <file>]
                [--keep-minified-content] [-v | -d | -dd] -u <URL>

Program options:
  -u,--url <URL>              URL(s) to fetch, could be a filename, a string a comma separated string list or a list
  -s,--scope <scope>          Set domain(s)/subdomain(s) as a valid scope instead of root_url. Multi-format (like --url)
  -m,--mapping-search         Attempt to recover '.js.map' files for all '.js' files found
  -o,--outdir <directory>     Directory to save the responses
  -x,--proxy <proxy>          Proxy to use for requests
  -H,--headers <header>...    Custom headers for the requests
  -r,--retry <num_retries>    Number of retries on failure [default: 1]
  -t,--threads <num_threads>  Number of threads to use [default: 5]
  -T,--timeout <seconds>      Timeout for each request in seconds [default: 8]

Filter options:
  --only-request-js-files     Input Filter: Clean '--url' argument to keep and only request '.js' files
  --only-save-js-files        Output filter: Save only beautified '.js' and '.js.map' files in output directory
  --only-save-orig-js-files   Output filter: Save only original '.js' and '.js.map' files in output directory
  --no-save-embedded-js       Output filter: No save in separated file embedded JavaScript code found in script tag
  --response-min-size <size>  Output filter: Skip all URLs whose response size is shorter than this value [default: 50]

Misc options
  --follow-redirect           Follow redirection when request responds an HTTP/3xx redirection
  --disable-cpath-filter      Disables consecutive paths detection and filter mechanism (ex: '../assets/assets/..')
  --disable-js-beautify       Disables the JavaScript beautification mechanism applied to '.js' files
  --disable-js-embedded       Disables the embedded JavaScript code recovery mechanism applied to non- '.js' files
  --disable-url-search        Disables the '.js' and '.chunk.js' recovering mechanism applied to fetched URLs
  --disable-proxy-check       Disables proxy check mechanism when proxy is present
  --disable-recursion         Disables recursion, the program stops when the first-level URLs are retrieved
  --headers-from-file <file>  Get raw request headers from file
  --keep-minified-content     Keep a copy of original minified content (.minified.js) for further unmapping with '.map'

General options:
  -v, --verbose               Enable verbose mode
  -d, --debug                 Show more details on what the program does under the hood
  -dd, --debug                Print Debug level 2 (with all classes debug_class output)
  -V, --version               Show version info
```

## More about supported arguments

### Arguments parsing

`JS Fetcher` allows to define some arguments in many ways:

- `-u,--url`, `-s,--scope` arguments can be a filename, a string, a comma-separated string list or a list (when `JS Fetcher` is used as a library);
- `-H,--headers` could be defined multiple times (like `curl`);
- `stdin` (with `-`) is supported for all these arguments.

For example, if you want to define several target urls (`-u,--url`), all the following commands produce the same result:

```c
js_fetcher -u /path/urls
js_fetcher -u http://www.example.com/app/
js_fetcher -u "http://target.tld.com/app/index, https://target.tld.com/file.js"
cat /path/urls | js_fetcher -u -
echo 'https://target.tld.com/file.js' | js_fetcher -u -
```

### Scope

By default, if the tool finds a complete URL that doesn't match the root URL, it marks it as out-of-scope (`OOS`).

For example, if all the `.js` files on the home page of **www.target.com** are linked to **assets.target.com**, these files will be rejected by default unless the argument `-s *.target.com` is passed to the program.


### Filters

It is also possible to filter the program's inputs/outputs:

 + **Input Filter** `--only-request-js-files`: Clean `--url` argument to keep and only request `.js` files;
 + **Output filter** `--only-save-js-files`: Save only `.js` files (beautified by default) and `.js.map` files in output directory.
 + **Output filter** `-only-save-min-js-files`: Save only original `.js` files (not beautified) and `.js.map` files in output directory.


### Internal JS beautify mechanism

By default, all fetched `.js` files are *beautified*, to make it easier and more efficient for the program to search for patterns in minified files.

The tool uses the python version of the [https://github.com/beautifier/js-beautify](https://github.com/beautifier/js-beautify) library, configured with the following options: 
 ```json
{
    "indent_size": 4,
    "indent_char": " ",
    "max_preserve_newlines": 2,
    "preserve_newlines": True,
    "keep_array_indentation": True,
    "break_chained_methods": True,
    "indent_scripts": "normal",
    "brace_style": "collapse",
    "space_before_conditional": False,
    "unescape_strings": True,
    "jslint_happy": True,
    "end_with_newline": True,
    "wrap_line_length": 200,
    "indent_inner_html": True,
    "comma_first": False,
    "e4x": False,
    "indent_empty_lines": False
}
```
If the main goal is to simply beautify JavaScript code, these parameters are adjustable in the source code, in the method `JSFetcher.get_beautifier_config()`, as well as in the 2 global variables of the same class `BEAUTIFIER_INDENT_SIZE` and `BEAUTIFIER_WRAP_LINE_LENGTH`.

:::warning
If you modify this configuration or disable beautification mechanism with the `--disable-js-beautify` option, the program may no longer find additional URLs in `.js` files.
:::

These parameters have been initially obtained (and can be tested) in the online version of this library tool [https://beautifier.io/](https://beautifier.io/)


## Practical examples

### Retrieved all JavaScript code of target(s)

Classic use of this tool. Takes a list of URLs and tries to recover as much JavaScript code as possible, saving each recovered file. A beautification operation is automatically applied to each valid javascript file.

```c
js_fetcher -u /tmp/urls.txt -s "*.target1.fr, *.target2.com" -r 2 -t 8 -T 10 -o /tmp/target-jscode/ --only-save-js-files --follow-redirect -d
```

### Just beautify JavaScript code of target(s)

If the goal is to simply beautify and save all the javascript files in a list of URLs, you can use the filters to keep only the javascript code as input/output and disable (or not) the search function of additional .js files.

```c
js_fetcher -u /tmp/urls.txt --only-request-js-files -t 8 -o /tmp/beautified-jscode/ --only-save-js-files --disable-url-search -v
```

### Get mapping file of any fetched JavaScript URLs

With the `-m,--mapping-search` option, the tool also includes a search feature of the mapping file (`.js.map`) associated with any fetched `.js` URLs.

```c
js_fetcher -u /tmp/urls.txt --only-request-js-files -t 8 -o /tmp/jscode-with-mapping/ -m -v
```

### Just replay a list of URLs through a proxy server (like Burp)

To replay a list of URLs through a proxy server, there's no need to waste time beautifying javascript code or searching for patterns to discover other URLs:

```c
js_fetcher -u /tmp/urls.txt -r 2 -t 8 -T 10 --follow-redirect -disable-js-beautify --disable-url-search -X http://127.0.0.1:8080
```

## Changelog

### Version 2.5

:::spoiler

Version improvements:

- Add `try_webpack_without_key` mode (global variable, True by default) to support a special case seen in ``Nuxt.js``.
  Example: `"js/" + { 0: "6aaec45", ... } [e] + ".js"` => `js/6aaec45.js`

:::

### Version 2.4

:::spoiler

Version improvements:

- Improve `REGEX_JS_URL_3` and `REGEX_END_BY_JS_OR_MAP` regexes to support mapping files ending by `.map` (instead of `.js.map`).

:::

### Version 2.3

:::spoiler

Version improvements:

- Fixed a bug allowing urls running on a port other than 80 or 443 (ex: `http://app.domain.com:3000/`) to be processed;
- Improve `REGEX_WEBPACK_2` regex to support a new loader format without a prefix folder and using a `.` (instead of `-`) as separator (encountered on an *AngularJS* frontend).

:::

### Version 2.2

:::spoiler

Version improvements:

- Add new `REGEX_WEBPACK_3` regex to support a special webpack loader (seen on *boutique.orange.fr*);
- Improve `REGEX_JS_URL_2` regex to support `.js` URLs containing a cache busting suffix (ex: `/assets/file.js?v=2`);
- Improve `REGEX_SCRIPT` regex and normalize *fake* `.embedded.js` URL(s).

:::

### Version 2.1

:::spoiler

Version improvements:

- Important bug fix in `UTF-8` string encoding, the default `strict` mode "lost" the content of part of the files instead of raising an exception. All encode/decode now set to `errors="replace"`;
- Added *fake urls* `.embedded.js` for files containing embedded JavaScript code to the results displayed by the tool on `STDOUT` and in log file.

:::

### Version 2.0

:::spoiler

Version improvements:

- Add a `references` key to fetched `.map` files containing the URL of the JavaScript file(s) linked to this mapping file:
 ![image](https://hackmd.io/_uploads/S1N2w58Wye.png)
 This reference will be used later by `js_unmap` when unmapping the `index.js` file to find out where it came from:
 ![image](https://hackmd.io/_uploads/By49tcLbJe.png)
- Added a new `--headers-from-file <file>` option to retrieve all headers present in a raw request pasted into a file;
- Improve some details in logging: Program shows more info in debug mode `-d` and `OOS` URLs now issue a warning and are displayed in all display modes;
- Add class comparison and hashing functions and docstrings harmonization.

:::

### Version 1.9

:::spoiler

Version improvements:

- Add support for files embedding JavaScript code (in `<script>` tags). Very useful when using the home page or `.html` files as a starting point. This behavior can be disabled with a new `--disable-js-embedded` option;
- Javascript source code embedded in `<script>` tags (in files not ending with `.js`) is saved by default in a file with the extension `embedded.js`. If you don't want to save this code, you can use the new `--no-save-embedded-js` option:
![image](https://hackmd.io/_uploads/Skb3wt5l1e.png)
- Add mapping coverage statistics, with two types of coverage percentages for `.map` files in the results URL list:
![image](https://hackmd.io/_uploads/rkvGKRtgJg.png)
  - Exact match coverage: percentage of files that have their exact corresponding mapping file;
  - Global coverage: percentage based on the total number of `.map` files versus other files.
- Internal doc, minor code refactoring and typo fix.

:::

### Version 1.8

:::spoiler

Version improvements:

- Major bug fix in `REGEX_JS_URL_3` regex;
- Get additional `.js` from `file` key value in source map files if present;
- Get additional `.js` file by removing `.map` in `.js.map` urls;
- Remove useless filter in `URLExtractor.extract_*`;
- Improve some details in debug_class logging (`-dd`).

:::

### Version 1.7

:::spoiler

Version improvements:

- Add new `--only-save-min-js-files` misc option to save the original minified content instead of his beautified version for further unmapping  with related `js.map` file;
- Small refactoring of `fetch_url()` method to deal with the new options;
- Parse discovered `.js.map` files to keep only valid `JSON` source map files;
- Format / pretty print content of discovered `.js.map` files before saving;
- Various minor bugs, internal doc and typo fix.

:::

### Version 1.6

:::spoiler

Version improvements:

- Add new `--keep-minified-content` misc option to keep, in addition to beautified `.js` file, a copy of original minified content (`.minified.js`) for further unmapping with related `js.map` file;
- Improve `REGEX_JS_URL_2` to avoid matching `.json` in addition of of `.js`;
- Improve `REGEX_JS_URL_3` regex to detect (sourceMappingURL|sourceURL), according to official documentation: https://tc39.es/source-map/#linking-generated-code;
- Add an addtionnal security filter to skip invalid `.js` or `.js.map` matches from general regex;
- Add python `set` support for library mode;
- Improve exception handling in proxy check method (now in Tools class);
- Various minor bugs, internal doc and typo fix.

:::

### Version 1.5

:::spoiler
Version improvements:

- Add `nextJS` support;
- Add embedded mapping files support; (`sourceMappingURL=data...base64,xxx`);
- Add consecutive paths detection (ex: `x/v1/assets/v1/assets/x.js` => `x/v1/assets/x.js`);
- Add 2 new misc options:
  + `--disable-recursion`: Disables recursion, the program stops when the first-level URLs are retrieved;
  + `--disable-cpath-filter`: Disables consecutive paths detection and filter mechanism. Useful for debug program;
- Avoid to beautify fake `HTTP/200` html error pages content;
- Various bugs & typo fix.
:::

### Version 1.1

:::spoiler
Version improvements:

- Improve relative paths (`../xxx`) management;
- Get URLs for `.js.map` files that differ from the `.js` filename;
- Various bugs & typo fix.
:::

### Version 1.0

Initial release.