UNPKG

node-libcurl-ja3

Version:

Node.js native bindings for libcurl-impersonate. Impersonate Chrome, Edge, Firefox and Safari TLS fingerprints.

355 lines (260 loc) 12.5 kB
# node-libcurl-ja3 [![NPM version][npm-image]][npm-url] [![license][license-image]][license-url] [npm-image]:https://img.shields.io/npm/v/node-libcurl-ja3.svg?style=flat-square [npm-url]:https://www.npmjs.org/package/node-libcurl-ja3 [license-image]:https://img.shields.io/npm/l/node-libcurl-ja3?style=flat-square [license-url]:https://raw.githubusercontent.com/andrewmackrodt/node-libcurl-ja3/develop/LICENSE ## Disclaimer This is a fork of [node-libcurl](https://github.com/JCMais/node-libcurl) using patches from [lexiforest/curl-impersonate](https://github.com/lexiforest/curl-impersonate) to impersonate the four major browsers: Chrome, Edge, Safari and Firefox. `node-libcurl-ja3` is able to perform TLS and HTTP handshakes that are identical to that of a real browser. **Only the following platforms are supported:** - Linux 64-bit (glibc based) - macOS Apple Silicon (M1+) Prebuilt binaries are provided for Node.js `20`, `22` and `24`. Any other version has not been tested and will need an environment capable of building the native module. Refer to [Important Notes on Prebuilt Binaries / Direct Installation](#important-notes-on-prebuilt-binaries--direct-installation) for a list of required system packages. Although the library is named `node-libcurl-ja3`, it **also supports** `http2` and `ja4` impersonation (e.g. Akamai). ## Table of Contents - [Quick Start](#quick-start) - [Install](#install) - [Impersonate Usage](#impersonate-usage) - [Simple Impersonate Request - Async / Await using curly](#simple-impersonate-request---async--await-using-curly) - [Simple Impersonate Request - Using Curl class](#simple-impersonate-request---using-curl-class) - [Simple Request - Async / Await using curly](#simple-request---async--await-using-curly) - [Simple Request - Using Curl class](#simple-request---using-curl-class) - [Setting HTTP headers](#setting-http-headers) - [Form Submission (Content-Type: application/x-www-form-urlencoded)](#form-submission-content-type-applicationx-www-form-urlencoded) - [MultiPart Upload / HttpPost libcurl Option (Content-Type: multipart/form-data)](#multipart-upload--httppost-libcurl-option-content-type-multipartform-data) - [Binary Data](#binary-data) - [API](#api) - [Special Notes](#special-notes) - [`READFUNCTION` option](#readfunction-option) - [Common Issues](#common-issues) - [Benchmarks](#benchmarks) - [Detailed Installation](#detailed-installation) - [Important Notes on Prebuilt Binaries / Direct Installation](#important-notes-on-prebuilt-binaries--direct-installation) - [Missing Packages](#missing-packages) - [Building on Linux](#building-on-linux) - [Building on macOS](#building-on-macos) - [Contributing](#contributing) - [Acknowledgments](#acknowledgments) ## Quick Start - This library cannot be used in a browser, it depends on native code. - There is no worker threads support at the moment. See [#169](https://github.com/JCMais/node-libcurl/issues/169) ### Install ```shell npm i node-libcurl-ja3 --save ``` or ```shell yarn add node-libcurl-ja3 ``` ### Impersonate Usage The following browser fingerprints are pre-configured: - Chrome 143 - Edge 143 - Firefox 144.0 - Safari 18.6 To learn how to configure custom impersonation options, refer to the folder [lib/impersonate/browser](./lib/impersonate/browser). For brevity, this section covers a single example for creating impersonate instances using the curly API and Curl class. To use impersonation with the examples following this section, adapt them to use either: - `impersonate` in place of `curly` - `Curl.impersonate` in place of `new Curl` #### Simple Impersonate Request - Async / Await using curly ```javascript const { Browser, impersonate } = require('node-libcurl-ja3'); const curly = impersonate(Browser.Chrome); const { data } = await curly.get('https://tls.browserleaks.com/json'); console.log(data.ja3n_hash); // 8e19337e7524d2573be54efb2b0784c9 ``` #### Simple Impersonate Request - Using Curl class ```javascript const { Browser, Curl } = require('node-libcurl-ja3'); const curl = Curl.impersonate(Browser.Chrome); curl.setOpt('URL', 'tls.browserleaks.com/json'); curl.setOpt('FOLLOWLOCATION', true); curl.on('end', function (statusCode, data, headers) { console.info(statusCode); console.info('---'); console.info(data.length); console.info('---'); console.info(this.getInfo('TOTAL_TIME')); this.close(); }); curl.on('error', curl.close.bind(curl)); curl.perform(); ``` ### Simple Request - Async / Await using curly **this API is experimental and is subject to changes without a major version bump** ```javascript const { curly } = require('node-libcurl-ja3'); const { statusCode, data, headers } = await curly.get('http://www.google.com') ``` Any option can be passed using their `FULLNAME` or a `lowerPascalCase` format: ```javascript const querystring = require('querystring'); const { curly } = require('node-libcurl-ja3'); const { statusCode, data, headers } = await curly.post('http://httpbin.com/post', { postFields: querystring.stringify({ field: 'value', }), // can use `postFields` or `POSTFIELDS` }) ``` JSON POST example: ```javascript const { curly } = require('node-libcurl-ja3') const { data } = await curly.post('http://httpbin.com/post', { postFields: JSON.stringify({ field: 'value' }), httpHeader: [ 'Content-Type: application/json', 'Accept: application/json' ], }) console.log(data) ``` ### Simple Request - Using Curl class ```javascript const { Curl } = require('node-libcurl-ja3'); const curl = new Curl(); curl.setOpt('URL', 'www.google.com'); curl.setOpt('FOLLOWLOCATION', true); curl.on('end', function (statusCode, data, headers) { console.info(statusCode); console.info('---'); console.info(data.length); console.info('---'); console.info(this.getInfo( 'TOTAL_TIME')); this.close(); }); curl.on('error', curl.close.bind(curl)); curl.perform(); ``` ### Setting HTTP headers Pass an array of strings specifying headers ```javascript curl.setOpt(Curl.option.HTTPHEADER, ['Content-Type: application/x-amz-json-1.1']) ``` ### Form Submission (Content-Type: application/x-www-form-urlencoded) ```javascript const querystring = require('querystring'); const { Curl } = require('node-libcurl-ja3'); const curl = new Curl(); const close = curl.close.bind(curl); curl.setOpt(Curl.option.URL, '127.0.0.1/upload'); curl.setOpt(Curl.option.POST, true) curl.setOpt(Curl.option.POSTFIELDS, querystring.stringify({ field: 'value', })); curl.on('end', close); curl.on('error', close); ``` ### MultiPart Upload / HttpPost libcurl Option (Content-Type: multipart/form-data) ```javascript const { Curl } = require('node-libcurl-ja3'); const curl = new Curl(); const close = curl.close.bind(curl); curl.setOpt(Curl.option.URL, '127.0.0.1/upload.php'); curl.setOpt(Curl.option.HTTPPOST, [ { name: 'input-name', file: '/file/path', type: 'text/html' }, { name: 'input-name2', contents: 'field-contents' } ]); curl.on('end', close); curl.on('error', close); ``` ### Binary Data When requesting binary data make sure to do one of these: - Pass your own `WRITEFUNCTION` (https://curl.haxx.se/libcurl/c/CURLOPT_WRITEFUNCTION.html): ```javascript curl.setOpt('WRITEFUNCTION', (buffer, size, nmemb) => { // something }) ``` - Enable one of the following flags: ```javascript curl.enable(CurlFeature.NoDataParsing) // or curl.enable(CurlFeature.Raw) ``` The reasoning behind this is that by default, the `Curl` instance will try to decode the received data and headers to utf8 strings, as can be seen here: https://github.com/JCMais/node-libcurl/blob/b55b13529c9d11fdcdd7959137d8030b39427800/lib/Curl.ts#L391 For more examples check the [examples folder](./examples). ## API This library provides Typescript type definitions. Almost all [CURL options](https://curl.haxx.se/libcurl/c/curl_easy_setopt.html) are supported, if you pass one that is not, an error will be thrown. For more usage examples check the [examples folder](./examples). ## Special Notes ### `READFUNCTION` option The buffer passed as first parameter to the callback set with the [`READFUNCTION`](https://curl.haxx.se/libcurl/c/CURLOPT_READFUNCTION.html) option is initialized with the size libcurl is using in their upload buffer (which can be set with [`UPLOAD_BUFFERSIZE`](https://curl.haxx.se/libcurl/c/CURLOPT_UPLOAD_BUFFERSIZE.html)), this is initialized using `node::Buffer::Data(buf);` which is basically the same than `Buffer#allocUnsafe` and therefore, it has all the implications as to its correct usage: https://nodejs.org/pt-br/docs/guides/buffer-constructor-deprecation/#regarding-buffer-allocunsafe So, be careful, make sure to return **exactly** the amount of data you have written to the buffer on this callback. Only that specific amount is going to be copied and handed over to libcurl. ## Common Issues See [COMMON_ISSUES.md](./COMMON_ISSUES.md) ## Benchmarks See [./benchmark](./benchmark) ## Detailed Installation The latest version of this package has prebuilt binaries (thanks to [node-pre-gyp](https://github.com/mapbox/node-pre-gyp/)) available for: - Node.js: Latest two versions on active LTS (see https://github.com/nodejs/Release) And on the following platforms: - Linux 64-bit (glibc based) - macOS Apple Silicon (M1+) Installing with `yarn add node-libcurl-ja3` or `npm install node-libcurl-ja3` should download a prebuilt binary and no compilation will be needed. The prebuilt binary is statically built with the following library versions, features and protocols: ``` Versions: libcurl/8.15.0-IMPERSONATE BoringSSL zlib/1.3.1 brotli/1.1.0 zstd/1.5.7 c-ares/1.34.5 nghttp2/1.63.0 ngtcp2/1.11.0 nghttp3/1.9.0 Protocols: dict file ftp ftps gopher gophers http https imap imaps ipfs ipns mqtt pop3 pop3s rtsp smb smbs smtp smtps telnet tftp ws wss Features: alt-svc AsynchDNS brotli ECH HSTS HTTP2 HTTP3 HTTPS-proxy HTTPSRR IPv6 Largefile libz NTLM SSL SSLS-EXPORT threadsafe UnixSockets zstd ``` If there is no prebuilt binary available that matches your system, or if the installation fails, then you will need an environment capable of compiling Node.js addons, which means: - [python 3.x](https://www.python.org/downloads/) installed - updated C++ compiler able to compile C++17. If you don't want to use the prebuilt binary even if it works on your system, you can pass a flag when installing: **With npm:** ```sh npm install node-libcurl-ja3 --build-from-source ``` **With yarn:** ```sh npm_config_build_from_source=true yarn add node-libcurl-ja3 ``` ### Important Notes on Prebuilt Binaries / Direct Installation The built binaries are statically linked with `BoringSSL`, `brotli`, `nghttp2`, `zlib` and `zstd`. #### Missing Packages The built binaries do not have support for `GSASL`, `GSS-API`, `HTTP3`, `IDN`, `LDAP`, `LDAPS`, `PSL`, `RTMP`, `SPNEGO`, `SSH`, `SSPI` or `TLS-SRP`. ### Building on Linux If you are on a debian based system, install the required dependencies by running: ```bash sudo apt install -qqy autoconf automake build-essential cmake curl libtool ninja-build pkg-config ``` Users for other distributions will need to find the equivalent packages and install via your package manager. ### Building on macOS On macOS you must have: - macOS >= 11.6 (Big Sur) - Xcode Command Line Tools - [Homebrew](https://brew.sh/) - Bash >= 5.0 (unconfirmed) You can check if you have Xcode Command Line Tools be running: ```sh xcode-select -p ``` It should return their path, in case it returns nothing, you must install it by running: ```sh xcode-select --install ``` Finally, install the remaining packages using homebrew: ```sh brew install automake bash cmake libtool make meson ninja ``` ## Contributing Read [CONTRIBUTING.md](./CONTRIBUTING.md) ## Acknowledgments - [JCMais/node-libcurl][a1] — provides the node libcurl bindings upon which this fork is created from. - [lexiforest/curl-impersonate][a2] — provides patches to add impersonate behaviour to curl. - [galihrivanto/node-libcurli][a3] — a similar fork based upon an older version of node-libcurl and libcurl-impersonate. - [Ossianaa/node-libcurl][a4] — a similar library which provided inspiration for setting fingerprints from JA3. [a1]: https://github.com/JCMais/node-libcurl [a2]: https://github.com/lexiforest/curl-impersonate [a3]: https://github.com/galihrivanto/node-libcurli [a4]: https://github.com/Ossianaa/node-libcurl