GithubHelp home page GithubHelp logo

danny-dasilva / cycletls Goto Github PK

View Code? Open in Web Editor NEW
801.0 26.0 158.0 38.8 MB

Spoof TLS/JA3 fingerprints in GO and Javascript

License: GNU General Public License v3.0

Go 73.42% TypeScript 23.47% JavaScript 3.11%
ja3 tls golang fingerprint fingerprinting bypass go http http2 https

cycletls's Introduction

CycleTLS

CycleTLS

Accepting Community Support and PR's

build GoDoc license Go Report Card npm version chat on Discord

If you have a API change or feature request feel free to open an Issue

πŸš€ Features

  • High-performance Built-in goroutine pool used for handling asynchronous requests
  • Custom header ordering via fhttp
  • Proxy support | Socks4, Socks5, Socks5h
  • Ja3 Token configuration

Table of contents

Dependencies

node ^v16.0
golang ^v1.21x

Installation

Node Js

$ npm install cycletls

Golang

$ go get github.com/Danny-Dasilva/CycleTLS/cycletls 

Usage

Example CycleTLS Request for Typescript and Javascript

You can run this test in tests/simple.test.ts

const initCycleTLS = require('cycletls');
// Typescript: import initCycleTLS from 'cycletls';

(async () => {
  // Initiate CycleTLS
  const cycleTLS = await initCycleTLS();

  // Send request
  const response = await cycleTLS('https://ja3er.com/json', {
    body: '',
    ja3: '771,4865-4867-4866-49195-49199-52393-52392-49196-49200-49162-49161-49171-49172-51-57-47-53-10,0-23-65281-10-11-35-16-5-51-43-13-45-28-21,29-23-24-25-256-257,0',
    userAgent: 'Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:87.0) Gecko/20100101 Firefox/87.0',
    proxy: 'http://username:[email protected]:443', 
  }, 'get');

  console.log(response);

  // Cleanly exit CycleTLS
  cycleTLS.exit();

})();

Example CycleTLS Request for Golang

package main

import (
	"log"
	"github.com/Danny-Dasilva/CycleTLS/cycletls"
)

func main() {

	client := cycletls.Init()

	response, err := client.Do("https://ja3er.com/json", cycletls.Options{
		Body : "",
		Ja3: "771,4865-4867-4866-49195-49199-52393-52392-49196-49200-49162-49161-49171-49172-51-57-47-53-10,0-23-65281-10-11-35-16-5-51-43-13-45-28-21,29-23-24-25-256-257,0",
		UserAgent: "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:87.0) Gecko/20100101 Firefox/87.0",
	  }, "GET");
	if err != nil {
		log.Print("Request Failed: " + err.Error())
	}
	log.Println(response)
}

Example using your own custom http.Client

import (
	"github.com/Danny-Dasilva/CycleTLS/cycletls"
	http "github.com/Danny-Dasilva/fhttp" // note this is a drop-in replacement for net/http
)

func main() {
	ja3 := "771,52393-52392-52244-52243-49195-49199-49196-49200-49171-49172-156-157-47-53-10,65281-0-23-35-13-5-18-16-30032-11-10,29-23-24,0"
	ua := "Chrome Version 57.0.2987.110 (64-bit) Linux"

 	 cycleClient := &http.Client{
 		Transport:     cycletls.NewTransport(ja3, ua),
 	 }

	resp, err := cycleClient.Get("https://tls.peet.ws/")
	...
}

Creating an instance

In order to create a cycleTLS instance, you can run the following:

JavaScript

// The initCycleTLS function spawns a Golang process that handles all requests concurrently via goroutine loops. 
const initCycleTLS = require('cycletls');
// import initCycleTLS from 'cycletls';

// Async/Await method
const cycleTLS = await initCycleTLS();
// .then method
initCycleTLS().then((cycleTLS) => {});

Golang

import (
	"github.com/Danny-Dasilva/CycleTLS/cycletls"
)

//The `Init` function initializes golang channels to process requests. 
client := cycletls.Init()

CycleTLS Alias Methods

The following methods exist in CycleTLS

cycleTLS(url, [config])

cycleTLS.get(url, [config])

cycleTLS.delete(url, [config])

cycleTLS.head(url, [config])

cycleTLS.options(url, [config])

cycleTLS.post(url, [config])

cycleTLS.put(url, config)

cycleTLS.patch(url, [config])

Url is not optional, config is optional

CycleTLS Request Config

{
  // URL for the request (required if not specified as an argument)
  url: "https://example.com"
  // Method for the request ("head" | "get" | "post" | "put" | "delete" | "trace" | "options" | "connect" | "patch")
  method: "get" // Default method
  // Custom headers to send
  headers: { "Authorization": "Bearer someexampletoken" }
  // Custom cookies to send
  Cookies: [{
    "name": "key",
    "value": "val",
    "path":  "/docs",
    "domain":  "google.com",
                "expires": "Mon, 02-Jan-2022 15:04:05 EST"
    "maxAge": 90,
    "secure": false,
    "httpOnly": true,
    "sameSite": "Lax"		
  }],
  // Body to send with request (must be a string - cannot pass an object)
  body: '',
  // JA3 token to send with request
  ja3: '771,4865-4867-4866-49195-49199-52393-52392-49196-49200-49162-49161-49171-49172-51-57-47-53-10,0-23-65281-10-11-35-16-5-51-43-13-45-28-21,29-23-24-25-256-257,0',
  // User agent for request
  userAgent: 'Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:87.0) Gecko/20100101 Firefox/87.0',
  // Proxy to send request through (must be in the same format)
  proxy: 'http://username:[email protected]:443',
  // Amount of seconds before request timeout (default: 7)
  timeout: 2,
  // Toggle if CycleTLS should follow redirects
  disableRedirect: true,
  // Custom header order to send with request (This value will overwrite default header order)
  headerOrder: ["cache-control", "connection", "host"],
  // Toggle if CycleTLS should skip verify certificate (If InsecureSkipVerify is true, TLS accepts any certificate presented by the server and any host name in that certificate.)
  insecureSkipVerify: false	
  // Forces CycleTLS to do a http1 handshake
  forceHTTP1: false	
}

CycleTLS Response Schema

{
  // Status code returned from server (Number)
  status: 200,
  // Body returned from the server (String)
  body: "",
  // Headers returned from the server (Object)
  headers: {
    "some": "header",
    ...
  },
  // FinalUrl returned from the server (String). This field is useful when redirection is active.
  finalUrl: "https://final.url/"	
}

Multiple Requests Example for Typescript and Javascript

If CycleTLS is being used by in a JavaScript environment, CycleTLS will spawn a Golang process to handle requests. This Golang process handles requests concurrently in a worker pool. Due to this, CycleTLS returns response objects as soon as they are made available (in other terms, CycleTLS processes requests as they are received, but responses are returned asynchronously so they will NOT be returned in the order requested)

If you are using CycleTLS in JavaScript, it is necessary to exit out of the instance to prevent zombie processes. The example below shows one way to approach cleanly exiting CycleTLS if you need to process multiple requests (note: keep in mind that calling the exit() function will kill any requests in progress). If your workflow requires requests running the entire time the process runs, modules such as exit-hook could serve as an alternative solution to cleanly exiting CycleTLS.

const initCycleTLS = require("cycletls");
// Typescript: import initCycleTLS from 'cycletls';

// Defining custom JA3 token and user agenton multiple requests,
  "https://httpbin.org/user-agent": {
    ja3: ja3,
    userAgent: userAgent,
  },
  "http://httpbin.org/post": {
    body: '{"field":"POST-VAL"}',
    method: "POST",
  },
  "http://httpbin.org/cookies": {
    cookies: [
      {
        name: "example1",
        value: "aaaaaaa",
        expires: "Mon, 02-Jan-2022 15:04:05 EST",
      },
    ],
  },
};

// Promises array of requests
const promises = [];

// Anonymous async function
(async () => {
  // Initiate CycleTLS
  const cycleTLS = await initCycleTLS();

  // Loop through requestDict (Object) defined above
  for (const url in requestDict) {
    // Fetch configs from requestDict (Object)
    const params = requestDict[url];

    // Send request (note: no waiting)
    const response = cycleTLS(
      url, {
        body: params.body ?? "", //?? is just setting defaults in this case
        ja3: params.ja3 ?? ja3,
        userAgent: params.userAgent ?? userAgent,
        headers: params.headers,
        cookies: params.cookies,
      }, params.method ?? "GET");

    // console.log the response object
    response.then((out) => {
      console.log(url, out);
    });

    // Push request to promise array
    promises.push(response);
  }

  // Wait for all requests to execute successfully
  Promise.all(promises).then(() => {
    // Cleanly exit CycleTLS one all requests have been received
    cycleTLS.exit();
  });
})();

Multiple Requests Example for Golang

The general expectation for golang packages is to expect the user to implement a worker pool or any other form of goroutine/asynchronous processing. This package includes a built in Queue method that leverages a worker pool/channels for long running asynchronous requests against a set of urls.

package main

import (
	"log"

	cycletls "github.com/Danny-Dasilva/CycleTLS/cycletls"
)

// Static variables
var (
	ja3       = "771,4865-4866-4867-49195-49199-49196-49200-52393-52392-49171-49172-156-157-47-53,0-23-65281-10-11-35-16-5-13-18-51-45-43-27-17513,29-23-24,0"
	userAgent = "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/101.0.4951.54 Safari/537.36"
)

// RequestConfig holds the configuration for each request.
type RequestConfig struct {
	URL     string
	Method  string
	Options cycletls.Options
}

func main() {
	client := cycletls.Init(true) // Initialize with worker pool

	// Define the requests
	requests := []RequestConfig{
		{
			URL:    "http://httpbin.org/delay/4",
			Method: "GET",
			Options: cycletls.Options{
				Ja3:       ja3,
				UserAgent: userAgent,
			},
		},
		{
			URL:    "http://httpbin.org/post",
			Method: "POST",
			Options: cycletls.Options{
				Body:      `{"field":"POST-VAL"}`,
				Ja3:       ja3,
				UserAgent: userAgent,
			},
		},
		{
			URL:    "http://httpbin.org/cookies",
			Method: "GET",
			Options: cycletls.Options{
				Ja3:       ja3,
				UserAgent: userAgent,
				Cookies: []cycletls.Cookie{
					{
						Name:  "example1",
						Value: "aaaaaaa",
					},
				},
			},
		},
	}

	// Queue the requests
	for _, req := range requests {
		client.Queue(req.URL, req.Options, req.Method)
	}

	// Asynchronously read responses as soon as they are available
	// They will return as soon as they are processed
	// e.g. Delay 3 will be returned last
	for i := 0; i < len(requests); i++ {
		response := <-client.RespChan
		log.Println("Response:", response)
	}

	// Close the client
	client.Close()
}

Dev Setup

If you would like to compile CycleTLS on your own, use the following commands:

Set module-aware mode go env -w GO111MODULE=off

Install golang dependencies go get github.com/Danny-Dasilva/CycleTLS/cycletls

install npm packages (this command handles the above)

npm install

To recompile index.ts in the src folder

npm run build

To recompile Golang files in the golang folder

All

npm run build:go

Windows

npm run build:go:windows:amd64

Linux

npm run build:go:linux:amd64

Mac

npm run build:go:mac:arm64

You can view the available compile options within the package.json

Questions

How do I set Cookies

There are two simple ways to interface with cookies

Javascript Simple Cookie Configuration

const initCycleTLS = require("cycletls");
(async () => {
  // Initiate cycleTLS
  const cycleTLS = await initCycleTLS();
  const response = await cycleTLS("https://httpbin.org/cookies", {
    cookies: {
      cookie1: "value1",
      cookie2: "value2",
    },
  });
  console.log(response.body);
  /* Expected
  {
    "cookies": {
      "cookie1": "value1",
      "cookie2": "value2"
    }
  }
  */
  cycleTLS.exit();
})();

In this simple example you can set the cookie name and value within an object

Javascript Complex Cookie Configuration

If you wish to have more fine grained control over cookie parameters you have access to the full underlying Go struct

here are the following values you can set

export interface Cookie {
  name: string;
  value: string;
  path?: string;
  domain?: string;
  expires?: string;
  rawExpires?: string;
  maxAge?: number;
  secure?: boolean;
  httpOnly?: boolean;
  sameSite?: string;
  unparsed?: string;
}

you can use them in a request as follows

const initCycleTLS = require("cycletls");
(async () => {
  // Initiate cycleTLS
  const cycleTLS = await initCycleTLS();
  const complexCookies = [
    {
      name: "cookie1",
      value: "value1",
      domain: "httpbin.org",
    },
    {
      name: "cookie2",
      value: "value2",
      domain: "httpbin.org",
    },
  ];

  const response = await cycleTLS("https://httpbin.org/cookies", {
    cookies: complexCookies,
  });

  console.log(response.body);
  /* Expected
  {
    "cookies": {
      "cookie1": "value1",
      "cookie2": "value2"
    }
  }
  */
  cycleTLS.exit();
})();

Golang Configure Cookies

package main

import (
    "github.com/Danny-Dasilva/CycleTLS/cycletls"
)

func main() {
    resp, err := client.Do("https://httpbin.org/cookies", cycletls.Options{
		Body:      "",
		Ja3:       "771,4865-4867-4866-49195-49199-52393-52392-49196-49200-49162-49161-49171-49172-51-57-47-53-10,0-23-65281-10-11-35-16-5-51-43-13-45-28-21,29-23-24-25-256-257,0",
		UserAgent: "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:87.0) Gecko/20100101 Firefox/87.0",
		Cookies: []cycletls.Cookie{{Name: "cookie1", Value: "value1"},
			{Name: "cookie2", Value: "value2"}},
    }, "GET")
    if err != nil {
      log.Print("Request Failed: " + err.Error())
    }
    log.Println(resp.Body)
    /* Expected
    {
      "cookies": {
        "cookie1": "value1", 
        "cookie2": "value2"
      }
      }
    */
    
    //Altenatively if you want access to values within a map
    log.Println(resp.JSONBody())
    /* Expected
    map[cookies:map[cookie1:value1 cookie2:value2]]
    */
}

Feel free to open an Issue with a feature request for specific file type support.

How do I use CookieJar in CycleTLS?

CookieJar in JS

const initCycleTLS = require("cycletls");

const tough = require("tough-cookie");
const Cookie = tough.Cookie;

(async () => {
  // Initiate cycleTLS and CookieJar
  const cycleTLS = await initCycleTLS();
  const cookieJar = new tough.CookieJar();

  // Capture a set cookie
  const firstResponse = await cycleTLS.get(
    "https://httpbin.org/cookies/set?freeform=test",
    {
      disableRedirect: true,
    }
  );
  
  // Now use the processCookies function to add the cookies from the response headers to the cookie jar
  await processCookies(
    firstResponse,
    "https://httpbin.org/cookies/set?freeform=test",
    cookieJar
  );
  // Now send a second to verify we have our cookies
  const secondResponse = await cycleTLS.get("https://httpbin.org/cookies", {
    headers: {
      cookie: await cookieJar.getCookieString("https://httpbin.org/cookies"),
    },
  });
  
  //verify cookies were set
  console.log(secondResponse.body)
  /* Expected
  {
    "cookies": {
      "freeform": "test"
    }
  }
  */
  cycleTLS.exit();
})();

async function processCookies(response, url, cookieJar) {
  if (response.headers["Set-Cookie"] instanceof Array) {
    response.headers["Set-Cookie"].map(
      async (cookieString) => await cookieJar.setCookie(cookieString, url)
    );
  } else {
    await cookieJar.setCookie(response.headers["Set-Cookie"], url);
  }
}

CookieJar in Golang

package main

import (
	"github.com/Danny-Dasilva/CycleTLS/cycletls"
	"log"
	"net/http/cookiejar"
	"net/url"
	"strings"
)

func main() {
	client := cycletls.Init()
	jar, err := cookiejar.New(nil)
  if err != nil {
      log.Fatal(err)
  }
	// First request to set cookie
	firstResponse, err := client.Do("https://httpbin.org/cookies/set?a=1&b=2&c=3", cycletls.Options{
		Body: "",
		Ja3:       "771,4865-4866-4867-49195-49199-49196-49200-52393-52392-49171-49172-156-157-47-53,0-23-65281-10-11-35-16-5-13-18-51-45-43-27-17513,29-23-24,0",
		UserAgent: "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/101.0.4951.54 Safari/537.36",
		DisableRedirect: true,
	},
		 "GET")
	if err != nil {
		log.Fatal(err)
	}
	firstURL, _ := url.Parse(firstResponse.FinalUrl)
  jar.SetCookies( firstURL, firstResponse.Cookies)


	// Second request to verify cookies, including the cookies from the first response
	secondResponse, err := client.Do("https://httpbin.org/cookies", cycletls.Options{
    Body: "",
    Ja3:       "771,4865-4866-4867-49195-49199-49196-49200-52393-52392-49171-49172-156-157-47-53,0-23-65281-10-11-35-16-5-13-18-51-45-43-27-17513,29-23-24,0",
    UserAgent: "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/101.0.4951.54 Safari/537.36",
    Headers: map[string]string{
        "Cookie": getHeadersFromJar(jar, firstURL),
    },
	}, "GET")
	if err != nil {
	    log.Fatal(err)
	}

	log.Println("Second Response body:", secondResponse.Body)
}


func getHeadersFromJar(jar *cookiejar.Jar, url *url.URL) string {
    cookies := jar.Cookies(url)
    var cookieStrs []string
    for _, cookie := range cookies {
        cookieStrs = append(cookieStrs, cookie.Name+"="+cookie.Value)
    }
    return strings.Join(cookieStrs, "; ")
}

How do I send multipart/form-data in CycleTLS

Javascript Text form-data

const initCycleTLS = require("cycletls");
const FormData = require('form-data');

(async () => {
  const cycleTLS = await initCycleTLS();

  const formData = new FormData();
  formData.append("key1", "value1");
  formData.append("key2", "value2");
  
  const response = await cycleTLS('http://httpbin.org/post', {
      body: formData,
      headers: {
          'Content-Type': 'multipart/form-data',
      },
  }, 'post');

  console.log(response);

  cycleTLS.exit();
})();

Javascript File form-data

const initCycleTLS = require("cycletls");
const FormData = require('form-data');
const fs = require('fs');

(async () => {
  const cycleTLS = await initCycleTLS();

  const formData = new FormData();
  const fileStream = fs.createReadStream("../go.mod");
  formData.append('file', fileStream);

  
  const response = await cycleTLS('http://httpbin.org/post', {
      body: formData,
      headers: {
          'Content-Type': 'multipart/form-data',
      },
  }, 'post');

  console.log(response);

  cycleTLS.exit();
})();

Golang Text form-data

package main

import (
	"bytes"
	"github.com/Danny-Dasilva/CycleTLS/cycletls"
	"log"
	"mime/multipart"
)

func main() {
	client := cycletls.Init()

	// Prepare a buffer to write our multipart form
	var requestBody bytes.Buffer
	multipartWriter := multipart.NewWriter(&requestBody)

	// Add form fields
	multipartWriter.WriteField("key1", "value1")
	multipartWriter.WriteField("key2", "value2")

	contentType := multipartWriter.FormDataContentType()
	// Close the writer before making the request
	multipartWriter.Close()

	response, err := client.Do("http://httpbin.org/post", cycletls.Options{
		Body: requestBody.String(),
		Headers: map[string]string{
			"Content-Type": contentType,
		},
	}, "POST")

	if err != nil {
		log.Print("Request Failed: " + err.Error())
	}

	log.Println(response.Body)
}

Golang file upload form-data

package main

import (
	"github.com/Danny-Dasilva/CycleTLS/cycletls"
	"bytes"
	"io"
	"log"
	"mime/multipart"
	"os"
)

func main() {
  client := cycletls.Init()

  // Prepare a buffer to write our multipart form
  var requestBody bytes.Buffer
  multipartWriter := multipart.NewWriter(&requestBody)

  // Add a file
  fileWriter, err := multipartWriter.CreateFormFile("fieldname", "filename")
  if err != nil {
      log.Fatal("CreateFormFile Error: ", err)
  }

  // Open the file that you want to upload
  file, err := os.Open("path/to/your/file")
  if err != nil {
      log.Fatal("File Open Error: ", err)
  }
  defer file.Close()

  // Copy the file to the multipart writer
  _, err = io.Copy(fileWriter, file)
  if err != nil {
      log.Fatal("File Copy Error: ", err)
  }

  // Close the writer before making the request
  contentType := multipartWriter.FormDataContentType()
  multipartWriter.Close()

  response, err := client.Do("http://httpbin.org/post", cycletls.Options{
      Body: requestBody.String(),
      Headers: map[string]string{
          "Content-Type": contentType,
      },
  }, "POST")

  if err != nil {
      log.Print("Request Failed: " + err.Error())
  }

  log.Println(response.Body)
}

If requested encoding helpers can be added to the repo for golang

How do I send a application/x-www-form-urlencoded Post request

Javascript application/x-www-form-urlencoded form

const initCycleTLS = require("cycletls");
(async () => {
  const cycleTLS = await initCycleTLS();

  const urlEncodedData = new URLSearchParams();
  urlEncodedData.append('key1', 'value1');
  urlEncodedData.append('key2', 'value2');

  const response = await cycleTLS('http://httpbin.org/post', {
      body: urlEncodedData,
      headers: {
          'Content-Type': 'application/x-www-form-urlencoded',
      },
  }, 'post');

  console.log(response);

  cycleTLS.exit();
})();

Golang application/x-www-form-urlencoded form

package main

import (
    "log"
	  "net/url"
    "github.com/Danny-Dasilva/CycleTLS/cycletls"
)

func main() {

	client := cycletls.Init()

	// Prepare form data
	form := url.Values{}
	form.Add("key1", "value1")
	form.Add("key2", "value2")

	response, err := client.Do("http://httpbin.org/post", cycletls.Options{
		Body: form.Encode(),
		Headers: map[string]string{
			"Content-Type": "application/x-www-form-urlencoded",
		},
	}, "POST")
	if err != nil {
		log.Print("Request Failed: " + err.Error())
	}
	log.Println(response.Body)
}

How do I download images?

Images with a Content-Type header of the following types are base 64 encoded.

Supported Image Types

  • image/svg+xml
  • image/webp
  • image/jpeg
  • image/png
  • application/pdf

To write them to a file you can use the below methods

Javascript Image Write to File

const initCycleTLS = require("cycletls");
var fs = require("fs");

//Function to write image to a file
const writeImage = (filename, data) => {
  let writeStream = fs.createWriteStream(filename);

  // write some data with a base64 encoding
  writeStream.write(data, "base64");
  writeStream.on("finish", () => {
    console.log(`wrote to file ${filename}`);
  });
  
  // close the stream
  writeStream.end();
};

(async () => {
  const cycleTLS = await initCycleTLS();
  // try {

  const jpegImage = await cycleTLS("http://httpbin.org/image/jpeg", {
    ja3: "771,4865-4867-4866-49195-49199-52393-52392-49196-49200-49162-49161-49171-49172-51-57-47-53-10,0-23-65281-10-11-35-16-5-51-43-13-45-28-21,29-23-24-25-256-257,0",
    userAgent:
      "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:87.0) Gecko/20100101 Firefox/87.0",
  });
  //Write Image
  writeImage("test.jpeg", jpegImage.body);

  cycleTLS.exit();
})();

Golang Image Write to File

package main

import (
    "encoding/base64"
    "os"
    "github.com/Danny-Dasilva/CycleTLS/cycletls"
)

func main() {

    client := cycletls.Init()
    response, err := client.Do("http://httpbin.org/image/jpeg", cycletls.Options{
      Body:      "",
      Ja3:       "771,4865-4866-4867-49195-49199-49196-49200-52393-52392-49171-49172-156-157-47-53,0-23-65281-10-11-35-16-5-13-18-51-45-43-27-21,29-23-24,0",
      UserAgent: "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.106 Safari/537.36",
    }, "GET")
    // Decode Base64
    dec, err := base64.StdEncoding.DecodeString(response.Body)
    if err != nil {
        panic(err)
    }
    //create file to write
    f, err := os.Create("test.jpeg")
    if err != nil {
        panic(err)
    }
    defer f.Close()
    //write b64 to file
    if _, err := f.Write(dec); err != nil {
        panic(err)
    }
    if err := f.Sync(); err != nil {
        panic(err)
    }
}

Additional file type support is planned.

Feel free to open an Issue with a feature request for specific file type support.

How do I set/force HTTP1

In golang set ForceHTTP1 in Options

package main

import (
	"github.com/Danny-Dasilva/CycleTLS/cycletls"
	"log"
)

func main() {
	client := cycletls.Init()
	response, err := client.Do("https://tls.peet.ws/api/all", cycletls.Options{
		ForceHTTP1: true,
	}, "GET")
	if err != nil {
		log.Print("Request Failed: " + err.Error())
	}
	log.Println(response.Body,) //You can verify the HTTP_Version in the response

}

In JS/TS set forceHTTP1 in Options

const initCycleTLS = require('cycletls');
// Typescript: import initCycleTLS from 'cycletls';

(async () => {
  const cycleTLS = await initCycleTLS();

  const response = await cycleTLS('https://ja3er.com/json', {
     body: '',
    ja3: '771,4865-4867-4866-49195-49199-52393-52392-49196-49200-49162-49161-49171-49172-51-57-47-53-10,0-23-65281-10-11-35-16-5-51-43-13-45-28-21,29-23-24-25-256-257,0',
    userAgent:
      'Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:87.0) Gecko/20100101 Firefox/87.0',
    forceHTTP1: false, //Set this field
  });

  console.log(response);
  //You can verify the HTTP_Version in the response
  cycleTLS.exit();

})();

Cross Compiling for other platforms

Natively the 3 Operating System types linux, darwin , windows should cover most use cases.

You can use the built in Golang cross compiling commands go build to compile for another operating system.

As an example for linux arm you need to pass in the GOOS and GOARCH arguments

$ GOOS=linux GOARCH=arm go build -o ./dist/index ./golang && chmod +x ./dist/index

With the above command you can simply run ./index and CycleTLS should function as intended.

Use this gist for different Operating Systems that support cross-compilation and feel free to open an Issue with a feature request for your specific operating system use case.

LICENSE

GPL3 LICENSE SYNOPSIS

TL;DR* Here's what the GPL3 license entails:

1. Anyone can copy, modify and distribute this software.
2. You have to include the license and copyright notice with each and every distribution.
3. You can use this software privately.
4. You can use this software for commercial purposes.
5. Source code MUST be made available when the software is distributed.
6. Any modifications of this code base MUST be distributed with the same license, GPLv3.
7. This software is provided without warranty.
8. The software author or license can not be held liable for any damages inflicted by the software.

More information on about the LICENSE can be found here

cycletls's People

Contributors

abler98 avatar chenghoward avatar danny-dasilva avatar deoxykev avatar lif0 avatar zebrapurring avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

cycletls's Issues

WebSocket support

Requested feature

It's a crucially missing functionality (for us at least πŸ˜„)

Proposed solution

Warning: this chart looks terrible
image

The proposed solution is adding an API for WebSocket communications.

Who makes the code?

We are interested in either contributing code or funding the issue.
You can contact us privately ([email protected]) to discuss this matter. If you give us directions on where/how to make the changes, we'll also be able to contribute directly.

Cannot use 'rt.dialTLSHTTP2'

Actual behavior

I get an error while building
Cannot use 'rt.dialTLSHTTP2' (type func(network string, addr string, _ *tls.Config) (net.Conn, error)) as the type func(network string, addr string, cfg *tls.Config) (net.Conn, error)

The DialTLS is accepting crypto/tls but its given as gitlab.com/yawning/utls.git
That's why its showing this error

Expected behavior
Should work normal without any errors

To Reproduce

Not sure how to reproduce, I changed the crypto/tls to gitlab.com/yawning/utls.git but that gives a lot of errors so I guess that's not the solution

Additional Information

  • Operating System information (e.g. Ubuntu 18.04): MacOS
  • Node version: 16
  • Golang version: 1.16

ARM64 binaries for Windows, Linux and macOS platforms

Requested feature The NPM package currently ships with the prebuilt binaries for x86-64, would be great if you can add arm64 binaries as well. Or as a more generic solution, configure the package.json to build the binaries from source when installing the library, if prebuilt binaries are not available.

Why the feature is needed This would allow running the library on platforms such as a Raspberry Pi, or natively on Apple Silicon macs.

Custom utls dependency for golang proxy tool unavailable

Actual behavior Unable to build the golang proxy tool due to private dependencies.

To Reproduce Steps to reproduce the behavior

  1. go env -w GO111MODULE=auto
  2. go get github.com/Danny-Dasilva/CycleTLS/cycletls returns error package gitlab.com/yawning/utls.git: cannot download, git://gitlab.com/yawning/utls uses insecure protocol

Additional Information

  • Operating System information: macOS 12.3 Monterey on arm64
  • Node version: v16.14.2
  • Golang version: go1.18.1 darwin/arm64

Disable auto-redirect

Add a redirect on/off

I personally need to handle the cookies before the redirection, and sadly I can't do it in the actual state of the module.
I would be incredibly greateful if this could be done

Extension {{ 17513 }} is not Supported

Description

I get this Extension {{ 17513 }} is not Supported from this JA3 771,4865-4866-4867-49195-49199-49196-49200-52393-52392-49171-49172-156-157-47-53,0-23-65281-10-11-35-16-5-13-18-51-45-43-27-17513,29-23-24,0

Issue Type

Support

Operating System

Windows 10, Mac OS

Node Version

Node 16.x

Golang Version

Go 16.x

Relevant Log Output

-> \nGet \"https://ja3er.com/json\": Extension {{ 17513 }} is not Supported by CycleTLS please raise an issue

Method in CycleTLS.Do isn't used

When you add the method in the Do paramaters it doesn't work but if you add it in the CycleTLS.option(), it works

When you add the method in the Do paramaters it should take the method and not add GET by default

client := cycletls.Init()
request, err := client.Do(urlString, options, "POST");

image
As you can see in this photo, Method is never used in the "Do" function

How to post ContentType multipart/form-data?

Description

How to post ContentType multipart/form-data?

Issue Type

Support

Operating System

Windows 10

Node Version

No response

Golang Version

Go 17.x

Relevant Log Output

No response

Client.Timeout or context cancellation while reading body

Actual behavior A clear and concise description of what the bug is.

Hello, first of all thanks for this this repository!

I have an issue with the timeout handling. In my project I use proxies, which seem to be very slow sometimes.
Therefor I was looking forward to implementing the recently added timeout feature.

Occasionally I am encountering the following issue although I have defined a timeout parameter for the client:

`Error: 2021/08/17 06:13:09 Parse Bytesnet/http: request canceled (Client.Timeout or context cancellation while reading body)

at Socket.<anonymous> (C:\xxxx\node_modules\cycletls\dist\index.js:67:33)
at Socket.emit (events.js:400:28)
at addChunk (internal/streams/readable.js:290:12)
at readableAddChunk (internal/streams/readable.js:265:9)
at Socket.Readable.push (internal/streams/readable.js:204:10)
at Pipe.onStreamRead (internal/stream_base_commons.js:188:23)

Error: 2021/08/17 06:13:09 Request Failed: net/http: request canceled (Client.Timeout or context cancellation while reading body)

at Socket.<anonymous> (C:\xxxx\node_modules\cycletls\dist\index.js:67:33)
at Socket.emit (events.js:400:28)
at addChunk (internal/streams/readable.js:290:12)
at readableAddChunk (internal/streams/readable.js:265:9)
at Socket.Readable.push (internal/streams/readable.js:204:10)
at Pipe.onStreamRead (internal/stream_base_commons.js:188:23)`

Expected behavior A clear and concise description of what you expected to
happen.

As adressed in #31 and recently added in your latest update. When using proxies, that are sometimes very slow I expected the request to timeout after the specific time, I set up. Most of the time it works. But sometimes the error occurs.

To Reproduce Steps to reproduce the behavior

`
async function test() {

const cycleTLS = await initCycleTLS();

const response = await cycleTLS("http://httpbin.org/delay/2", {
body: "",
ja3: "771,4865-4867-4866-49195-49199-52393-52392-49196-49200-49162-49161-49171-49172-51-57-47-53-10,0-23-65281-10-11-35-16-5-51-43-13-45-28-21,29-23-24-25-256-257,0",
userAgent: "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:87.0) Gecko/20100101 Firefox/87.0",
timeout: 1,
}, "get");

console.log(response.status);
cycleTLS.exit()
};
`
Additional Information

  • Operating System: Windows 10 @ [email protected]
  • Node version: Node.js v14.15.1
  • Golang version: go1.16.6 windows/amd64

CycleTLS: JSON BODY support

I am trying to post data to some API where server is accepting only json object. As CycleTLS supports String Body only, is there any way I can patch this?
Thanks

initCycleTLS is not a function

Hi!
Looking for some help,
Using this from the example:

const initCycleTLS = require('cycletls');
// Typescript: import initCycleTLS from 'cycletls';

(async () => {
  const cycleTLS = await initCycleTLS();

    const response = cycleTLS('https://ja3er.com/json', {
      body: '',
      ja3: '771,4865-4867-4866-49195-49199-52393-52392-49196-49200-49162-49161-49171-49172-51-57-47-53-10,0-23-65281-10-11-35-16-5-51-43-13-45-28-21,29-23-24-25-256-257,0',
      userAgent: 'Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:87.0) Gecko/20100101 Firefox/87.0',
      proxy: 'http://username:[email protected]:443'
    }, 'get');

    response.then((out) => {
      console.log(out)
    })
	
    cycleTLS.exit()

})();

We always get initCycleTLS is not a function, all dependencies are installed, do you know why this could be happening?

Thank you for your time,
Best,

Do not exit the whole process on error/crash but reinitialise CycleTLS

Requested feature
I think there should be a user configurable option (like 'restartOnCrash' or similar), that is checked in cleanExit, and after killing the child process by pid, skips the process.exit(); lines, and instead, calls a function, that closes the ws server (important, to be able to use the port again) and runs and waits for initCycleTLS again, so an unexpected error in the Go parts wont result in closing down the whole application using this library - but re-spawns a working child.

Why the feature is needed
Errors can happen anytime.

Proposed solution
I think the best solution would be that after an unexpected error/crash, if a specified option is set (or either by default), the invoked await cycleTLS(url, ... would only resolve (or reject) if

  • the error is handled (logged)
  • the child process is killed
  • the ws server is closed
  • the initCycleTLS is re-called and resolved as ready

This way, when someone calls cycleTLS(...) with await, no matter if it failed - even with a crash - it won't break the workflow of the main application (or exit) and someone can expect an "always available" submodule that they can call again, anytime.

Golang cmd window not hiding

Actual behavior
Golang cmd window opens and remains visible until exit.

Expected behavior
Golang cmd window is never visible.

To Reproduce Steps to reproduce the behavior

  1. Run example code

Additional Information

  • Operating System information:
    Windows 10 Pro
    Version 20H2
    OS build 19042.1052

  • Node version: v14.17.2

  • Golang version: ?

image

Proposed solution:

My Chrome TLS Fingerprint is giving error : error: remote error: tls: error decoding message map[]

My current chrome fingerprint i.e. 771,4865-4866-4867-49195-49199-49196-49200-52393-52392-49171-49172-156-157-47-53,0-23-65281-10-11-35-16-5-13-18-51-45-43-27-21,,

Is failing with this error error: remote error: tls: error decoding message map[]

It looks like last two parameters of my ja3 fingerprint are blank... and with those two blank, I am getting this error. If I fill those two parameters also with some previous value like 29-23-24,0

Then I stop getting this error and it works fine for me... But right now I am getting both of those values blank in Chrome, Firefox as well as Edge...

Can somebody please help me what I am missing out on?

Support Socks5/4

Hi there,
Please support socks5 feature to proxy. I tried 'proxy: 'socks5://127.0.0.1:1080' but seems like it does not supported right now.
Output:

scheme socks5 is not supported

Decompress a (gzip/br/etc) compressed response body before returning it

Requested feature
If the request results in a compressed response, decompress the data before setting the value to response.body

Why the feature is needed
If we are sending a request with Accept-Encoding in the headers (for example: 'Accept-Encoding': 'gzip, deflate, br') and the server responds with a compressed (for example gzipped) response, response.body will store this compressed "non-processable" raw data (which also possibly gets corrupted somehow, but this is just an assumption based on the fact I failed to decompress it on the first few tries with zlib.gunzipSync [Error: incorrect header check]). I tried to fix this and send a PR, but I'm afraid this has to be fixed on the Go side, which is unfortunately out of my knowledge.

Not Able to Read Cookies in the redirected requests...

I am able to get cookies from a request that is being generated by a redirect... Here is the scenario...

  1. I hit URL1... URL1 sends back 2 cookies and then Redirects to URL2.
  2. URL2 opens without any cookies...

Now I am not able to get any cookies if I set disableRedirect to false. And I am not getting redirected if I set disableRedirect to True...

What should be done in this case?

Known JA3 token parsing issue

Actual behavior TLS handshake fails on http2 servers

Expected behavior TLS handshake succeeds on http2 servers

To Reproduce Steps to reproduce the behavior

  1. use a known ja3 token and request a url with exclusive http2 support such as https://http2.pro/api/v1

Additional Information
After investigation this is a known issue with the way ja3 tokens are being parsed currently in the repo, for http1 servers this should not affect anything but for http2 servers the handshake will fail. Along with this this incorrect parsing produces an incorrect ja3 hash which can be detected. There will be a PR made as soon as this is figured out.


The issue can be found in the utls.SupportedCurvesExtension and utls.KeyShareExtension for chrome which uses the GREASE_PLACEHOLDER along with this the SupportedSignatureAlgorithms needs to be parsed from the JA3 string in order to generate the correct signature scheme relating to the string

Some Ja3 strings causing stackoverflow

JA3 strings listed below causing panic.

769,49200-49196-49192-49188-49172-49162-165-163-161-159-107-106-105-104-57-56-55-54-136-135-134-133-49202-49198-49194-49190-49167-49157-157-61-53-132-49199-49195-49191-49187-49171-49161-164-162-160-158-103-64-63-62-51-50-49-48-154-153-152-151-69-68-67-66-49201-49197-49193-49189-49166-49156-156-60-47-150-65-7-49169-49159-49164-49154-5-4-49170-49160-22-19-16-13-49165-49155-10-255,0-11-10-35-13-15,23-25-28-27-24-26-22-14-13-11-12-9-10,0-1-2

769,52244-52243-52245-49195-49199-158-49162-49172-57-49161-49171-51-49159-49169-156-53-47-5-4-10-255,0-23-35-13-5-13172-18-16-30032-11-10,23-24-25,0

771,49200-49196-49192-49188-49172-49162-165-163-161-159-107-106-105-104-57-56-55-54-136-135-134-133-49202-49198-49194-49190-49167-49157-157-61-53-132-49199-49195-49191-49187-49171-49161-164-162-160-158-103-64-63-62-51-50-49-48-154-153-152-151-69-68-67-66-49201-49197-49193-49189-49166-49156-156-60-47-150-65-7-49169-49159-49164-49154-5-4-49170-49160-22-19-16-13-49165-49155-10-255,0-11-10-35-13-15,23-25-28-27-24-26-22-14-13-11-12-9-10,0-1-2

771,49195-49199-49196-49200-52393-52392-49171-49172-156-157-47-53-10,18-16-30032-11-10-65281-0-23-35-13-5,29-23-24,0

771,49200-49196-49202-49198-49199-49195-49201-49197-163-159-162-158-49192-49188-49172-49162-49194-49190-49167-49157-107-106-57-56-49191-49187-49171-49161-49193-49189-49166-49156-103-64-51-50-49170-49160-49165-49155-136-135-69-68-22-19-157-156-61-53-60-47-132-65-10-49169-49159-49164-49154-5-255,0-11-10-35-13-15,25-24-23,0-1-2

771,4865-4866-4867-49195-49199-49196-49200-52393-52392-49171-49172-156-157-47-53,0-23-65281-10-11-35-16-5-13-18-51-45-43-27-21-41,29-23-24,0

771,4865-4866-4867-49195-49199-49196-49200-52393-52392-49171-49172-156-157-47-53,0-23-65281-10-11-35-16-5-13-18-51-45-43-27-41,29-23-24,0

771,52244-52243-52245-49195-49199-158-49162-49172-57-49161-49171-51-49159-49169-156-53-47-5-4-10-255,0-23-35-13-5-13172-18-16-30032-11-10,23-24,0
771,52244-52243-52245-49195-49199-158-49162-49172-57-49161-49171-51-49159-49169-156-53-47-5-4-10-255,0-23-35-13-5-13172-18-16-30032-11-10,23-24,0

771,52393-52392-49195-49199-49196-49200-49171-49172-156-157-47-53-10,65281-0-23-35-13-5-18-16-30032-11-10-27,29-23-24,0

771,52244-52243-49195-49199-158-49162-49172-57-49161-49171-51-156-53-47-10,65281-0-23-35-13-5-13172-18-16-30032-11-10,23-24,0

771,52244-52243-52245-49172-49162-57-56-53-49170-49160-22-19-10-49199-49195-49171-49161-162-158-51-50-156-47-49169-49159-5-4-255,0-35-13-13172-30032-11-10,25-24-23,0

771,49200-49196-49202-49198-49199-49195-49201-49197-163-159-162-158-49192-49188-49172-49162-49194-49190-49167-49157-107-106-57-56-49191-49187-49171-49161-49193-49189-49166-49156-103-64-51-50-49170-49160-49165-49155-136-135-69-68-22-19-157-156-61-53-60-47-132-65-10-49169-49159-49164-49154-5-255,0-11-10-35-13-15-21,14-13-25-11-12-24-9-10-22-23-8-6-7-20-21-4-5-18-19-1-2-3-15-16-17,0-1-2

771,52244-52243-52245-49195-49199-158-49162-49172-57-49161-49171-51-156-53-47-10-255,0-23-35-13-5-13172-18-16-30032-11-10,23-24,0

runtime: goroutine stack exceeds 1000000000-byte limit
runtime: sp=0xc021b71460 stack=[0xc021b70000, 0xc041b70000]

Getting 403 in http2 site

Actual behavior It gives 403 if the site Is expecting http2 but we connect via http1.1

Expected behavior It should give 200 status code

To Reproduce Not sure how to reproduce
but I'm still not sure

More info
So, I tried to send request with regular residential proxy to a site but that gave 403. Then, I checked the site and it was sent as http2 and that was fine in browser. But when I do with this spoof TLS I get 403
tried without proxy too, same issue. not sure what is wrong

With proxy for http as schema it gives 403
With proxy for https as schema it gives a error http: server gave HTTP response to HTTPS client

Additional Information

  • Operating System information (e.g. Ubuntu 18.04): MacOS 12.2.1, windows 11
  • Node version: xx
  • Golang version: 1.16

Set User-Agent for the CONNECT request from the config

Requested feature: For consistency, set the "User-Agent" from the config for the CONNECT request too, not just for the actual get/post/etc request.

Why the feature is needed: I already found that there is a commented out line in connect.go that used to (?) set the User-Agent and that would be good to use the same user-agent for every request to not "confuse" any server with the difference.

Also, thank you for actively maintaining the one and only up to date TLS fingerprint changer for NodeJS!
Extra question: Just out of curiosity, which part of the code requires the use of Go that can not be reproduced with pure JS?

Spoofed TLS/JA3 fingerprint is detected by CloudFlare Detection

Hi Danny!
You project works well and there is no problem with GET requests, until u need to send POST request
For example =:>

const initCycleTLS = require('cycletls');
// Typescript: import initCycleTLS from 'cycletls';
(async() => {
    // Initiate CycleTLS
    const cycleTLS = await initCycleTLS();
    // Send request
    const response = await cycleTLS('https://betway.com/en/sports/evt/9578187', {
        body: '{"EventId":9578187,"LanguageId":1,"ClientTypeId":2,"BrandId":3,"JurisdictionId":2,"ClientIntegratorId":1,"ScoreboardRequest":{"ScoreboardType":0,"IncidentRequest":{}},"BrowserId":5,"ApplicationVersion":"","BrowserVersion":"100.0","SessionId":null,"TerritoryId":165,"CorrelationId":"59ff2df8-6099-425b-9293-a454121b8fe7","VisitId":"1085fcbc-400d-4aa9-a0fc-89a04e5a9a9b","ViewName":"sports","JourneyId":"bb37cce7-3703-48db-b51f-c6d18fba73c3"}',
        ja3: '771,4865-4867-4866-49195-49199-52393-52392-49196-49200-49162-49161-49171-49172-156-157-47-53,0-23-65281-10-11-35-16-5-51-43-13-45-28-21,29-23-24-25-256-257,0',
        headers: {
            "Host": "sportsapi.betway.com",
            "Accept": "application/json; charset=UTF-8",
            "Accept-Language": "en-US,en;q=0.5",
            "Connection": "keep-alive",
            "Content-Length": "440",
            "Content-Type": "application/json; charset=UTF-8",
            "Origin": "https://betway.com",
            "Referer": "https://betway.com/",
            "Sec-Fetch-Dest": "empty",
            "Sec-Fetch-Mode": "cors",
            "Sec-Fetch-Site": "same-site",
            "TE": "trailers",
        },
        cookies: [{
            "_fbp": "fb.1.1650841035798.971215073",
            "_ga:": "GA1.2.1003986219.1650841035",
            "_gcl_au": "1.1.1603919891.1651529638",
            "_scid": "94056155-3550-446b-8fba-74f38783cc9e",
            "_tgci": "483ed97e-c031-528c-b9b5-a69746d796d5",
            "_tglksd": "eyJzIjoiYjc1ZDBmNjQtNGQ2Ny01ZWVlLWIzNTItOGRhYWM4NDYxYzg4Iiwic3QiOjE2NTE1NzYxMjg4OTh9",
            "_tgpc": "44b2b253-23f7-5162-915c-d4381a35f1d7",
            "aam_uuid": "39152609555483373423854102918648869002",
            "AMCV_74756B615BE2FD4A0A495EB8@AdobeOrg": "359503849|MCIDTS|19115|MCMID|39390739662373507403855976085626163040|MCAAMLH-1652180928|6|MCAAMB-1652180928|6G1ynYcLPuiQxYZrsz_pkqfLG9yMXBpb2zX5dvJdYQJzPXImdj0y|MCCIDH|-897270710|MCOPTOUT-1651583328s|NONE|MCAID|NONE|vVersion|5.0.1",
            "BETWAY_ENSIGHTEN_PRIVACY_Analytics": "1",
            "BETWAY_ENSIGHTEN_PRIVACY_Marketing": "1",
            "bw_BrowserId": "76501619282281851930349603208014741540",
            "bw_SessionId": "ea1e718a-00ec-4652-b15f-c02f98ff6854",
            "bwui_cookieToastDismissed": "true",
            "COOKIE_POLICY_ACCEPTED": "true",
            "ens_firstVisit": "1651533525209",
            "s_ecid": "MCMID|39390739662373507403855976085626163040",
            "SpinSportVisitId": "1085fcbc-400d-4aa9-a0fc-89a04e5a9a9b",
            "ssc_btag": "58bf7482-9750-46ac-84ea-545f0b8e6690",
            "ssc_DeviceId": "ad92ae8e-39af-47fa-b0c8-5237452e9620",
            "ssc_DeviceId_HttpOnly": "ad92ae8e-39af-47fa-b0c8-5237452e9620",
            "StaticResourcesVersion": "12.41.0.6",
            "TrackingVisitId": "58bf7482-9750-46ac-84ea-545f0b8e6690",
            "userLanguage": "en"
        }],
        userAgent: 'Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:100.0) Gecko/20100101 Firefox/100.0',
        // proxy: 'http://username:[email protected]:443'
    }, 'post');

    console.log(response);

    // Cleanly exit CycleTLS
    cycleTLS.exit();

})();

I have '403' error

How to connect to GraphQL API

Description

func main() {

	client := cycletls.Init()
       	query := map[string]string{
		"query": `
			characters {
				results {
					name
					status
					species
					type
					gender
				}
        `,
	}
	jsonValue, _ := json.Marshal(query)
	response, err := client.Do("https://rickandmortyapi.com/graphql/", cycletls.Options{
		Body : string(query),
		Ja3: "771,4865-4867-4866-49195-49199-52393-52392-49196-49200-49162-49161-49171-49172-51-57-47-53-10,0-23-65281-10-11-35-16-5-51-43-13-45-28-21,29-23-24-25-256-257,0",
		UserAgent: "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:87.0) Gecko/20100101 Firefox/87.0",
	  }, "POST");
	if err != nil {
		log.Print("Request Failed: " + err.Error())
	}
	log.Println(response)
}

I have 500 error back, so is it possible to do ?
Thx in advance

Issue Type

Others

Operating System

Linux, Ubuntu

Node Version

No response

Golang Version

Other

Relevant Log Output

No response

Address already in use

events.js:292
throw er; // Unhandled 'error' event
^

Error: listen EADDRINUSE: address already in use :::9119
←[90m at Server.setupListenHandle [as _listen2] (net.js:1318:16)←[39m
←[90m at listenInCluster (net.js:1366:12)←[39m
←[90m at Server.listen (net.js:1452:7)←[39m
at new WebSocketServer (C:\Users\Mobeen\node_modules\←[4mws←[24m\lib\websocket-server.js:75:20)
at new Golang (C:\Users\Mobeen\node_modules\←[4mcycletls←[24m\dist\index.js:39:23)
at C:\Users\Mobeen\node_modules\←[4mcycletls←[24m\dist\index.js:94:26
at new Promise ()
at initCycleTLS (C:\Users\Mobeen\node_modules\←[4mcycletls←[24m\dist\index.js:88:12)
at setEmail (C:\Users\Mobeen\Downloads\cheetahv20-main\mesh.js:68:26)
at atcTLS (C:\Users\Mobeen\Downloads\cheetahv20-main\mesh.js:62:7)
Emitted 'error' event on WebSocketServer instance at:
←[90m at Server.emit (events.js:315:20)←[39m
←[90m at emitErrorNT (net.js:1345:8)←[39m
←[90m at processTicksAndRejections (internal/process/task_queues.js:80:21)←[39m {
code: ←[32m'EADDRINUSE'←[39m,
errno: ←[33m-4091←[39m,
syscall: ←[32m'listen'←[39m,
address: ←[32m'::'←[39m,
port: ←[33m9119←[39m
}

Getting this error. I think its due to port issue.

Issue in Extension 34 and 41

CycleTLS doesn't request to any site with any valid JA3

I dont know the issue but the error is in extension number 34.

JA3 used: 771,4865-4867-4866-49195-49199-52393-52392-49196-49200-49162-49161-49171-49172-156-157-47-53-10,0-23-65281-10-11-16-5-34-51-43-13-45-28-41,29-23-24-25-256-257,0

Edit: the errors, that i get are in extension 34 and 41.

Spoofed TLS/JA3 fingerprint is detected by some sites

Actual behavior
It looks like that there are a few websites (I mean services, but not naming them for obvious reasons) that can detect, that the TLS/JA3 fingerprint is spoofed and return with a 403 Forbidden status code. Unfortunately I have not found the reason yet.

Expected behavior
No server should be able to detect that the fingerprint is spoofed.

To Reproduce

  1. Find out the User-Agent and the JA3 fingerprint string of your browser
  2. Open the website with your browser, copy every request header
  3. Set up a simple script with the minimal example, change the URL to the same above, add the original headers of your browser and the JA3 string to the options.
  4. Run the script
  5. Error: 403 Forbidden

Additional Information

I'm quite new to TLS spoofing but tried to find out and fix what causes this. Unfortunately the only difference I noticed between my browser and my script using Wireshark (for the first time) is that CycleTLS used TLSv1.2 while my browser used TLSv1.3 during the Client Hello. Maybe the server knows that the browser with this fingerprint should use v1.3 and blocked the request because of that?

OS: MacOS Catalina 10.15.7
Browser: Firefox v92.0.1
UA: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:92.0) Gecko/20100101 Firefox/92.0
JA3: 771,4865-4867-4866-49195-49199-52393-52392-49196-49200-49162-49161-49171-49172-156-157-47-53-10,0-23-65281-10-11-35-16-5-51-43-13-45-28-21,29-23-24-25-256-257,0

Reusing connection and MaxIdleConnsPerHost option add

Hello, as i understand every request CycleTls makes a new connection.
Is there any possible to create someting like ordinary http client with some options like ja3 and headers and reuse connection instead of creating new one every time.

right now i'm using something like this

tr, err := NewTransport(ja3sting)
tr.MaxIdleConnsPerHost = 50
httpClient = &http.Client{Transport: tr, Timeout: 10 * time.Second}

Add a timeout feature

Add a timeout feature in the cycletls.Options map

Could be really useful for people who are using really shitty proxies or are trying to MITM and modify the requests (my personnal use case)

Client returns unrelated status codes for system errors

Actual behavior A clear and concise description of what the bug is.
When sending a few dozen requests at a time I get "too many open files" and "no such host" system errors for which CycleTLS returns a response with status codes 401, 408 or 421 instead of an error, even though the request was not sent at all. The api I am using responds with useful data for status 401 so it was a bit tricky to solve this error.

Expected behavior A clear and concise description of what you expected to
happen.
Return an error instead of a response with the custom status codes when the request fails to send due to system error.

To Reproduce Steps to reproduce the behavior

  1. Send requests until limit of file descriptors is reached while logging the status code and response body of each request

Additional Information

  • Operating System information (e.g. Ubuntu 18.04): MacOS 12.3
  • Node version: N/A
  • Golang version: 1.18

presharedkey Extension support.

Right now i see using extension "41" pre_shared_key is not possible. But there are some severs that checks them.

I didn't find if even in native go client there is support for that.

Compile go sources as a library (.dll .so)

Hello!

Thank you for a very useful project! ❀️ I am trying to integrate it into current project and came across some limitation due to socket usage. Using it in production\consumer app, assigning port to each consumer brings additional complexity. My suggestion is to compile .exe as a c library as explained here and call function from it. As additional bonus, this library could be called from C, Python, Ruby, Java... basically everything! Let me know what you think!

Thanks!

main.go:4:2: local import "./cycletls" in non-local package

Actual behavior

I can't install the package.

Expected behavior

The package installs successfully.

To Reproduce Steps to reproduce the behavior

mkdir /tmp/testing
cd /tmp/testing
github.com/testing/testing
go get github.com/Danny-Dasilva/CycleTLS # /Users/clouedoc/go/pkg/mod/github.com/!danny-!dasilva/[email protected]/main.go:4:2: local import "./cycletls" in non-local package

Additional Information

  • Golang version: go version go1.17.6 darwin/arm64

builder error

`c:\tls\CycleTLS>go get -u -v github.com/Danny-Dasilva/CycleTLS/cycletls
github.com\Danny-Dasilva\CycleTLS (download)
github.com\Danny-Dasilva\fhttp (download)

cd .; git ls-remote https://gitlab.com/yawning/utls

fatal: Cannot prompt because user interactivity has been disabled.
fatal: could not read Username for 'https://gitlab.com': terminal prompts disabled

cd .; git ls-remote git+ssh://gitlab.com/yawning/utls

Host key verification failed.
fatal: Could not read from remote repository.
`

Certain JA3 tokens appear to be failing

Actual behavior A clear and concise description of what the bug is.

I apologize if this is related to #14 - I wasn't sure.

I'm getting an error when using the following JA3 token:

771,4866-4867-4865-49199-49195-49200-49196-158-49191-103-49192-107-163-159-52393-52392-52394-49327-49325-49315-49311-49245-49249-49239-49235-162-49326-49324-49314-49310-49244-49248-49238-49234-49188-106-49187-64-49162-49172-57-56-49161-49171-51-50-157-49313-49309-49233-156-49312-49308-49232-61-60-53-47-255,0-11-10-35-22-23-13-43-45-51,29-23-1035-25-24,0-1-2

The error looks like a spam similar to the following:

goroutine 132 [chan receive]:
main.worker(0xc00010a060, 0xc00010a0c0)
        /home/runner/work/CycleTLS/CycleTLS/golang/index.go:210 +0xe5
created by main.workerPool
        /home/runner/work/CycleTLS/CycleTLS/golang/index.go:204 +0x59

goroutine 133 [chan receive]:
main.worker(0xc00010a060, 0xc00010a0c0)
        /home/runner/work/CycleTLS/CycleTLS/golang/index.go:210 +0xe5
created by main.workerPool
        /home/runner/work/CycleTLS/CycleTLS/golang/index.go:204 +0x59

    at Socket.<anonymous> (xxxxx\node_modules\cycletls\dist\index.js:67:33)
    at Socket.emit (node:events:369:20)
    at addChunk (node:internal/streams/readable:313:12)
    at readableAddChunk (node:internal/streams/readable:288:9)
    at Socket.Readable.push (node:internal/streams/readable:227:10)
    at Pipe.onStreamRead (node:internal/stream_base_commons:190:23)
Error: Command failed: taskkill /pid 22720 /T /F
ERROR: The process with PID 20108 (child process of PID 22720) could not be terminated.
Reason: There is no running instance of the task.

    at ChildProcess.exithandler (node:child_process:326:12)
    at ChildProcess.emit (node:events:369:20)
    at maybeClose (node:internal/child_process:1067:16)
    at Process.ChildProcess._handle.onexit (node:internal/child_process:301:5) {
  killed: false,
  code: 255,
  signal: null,
  cmd: 'taskkill /pid 22720 /T /F'
}

Expected behavior A clear and concise description of what you expected to
happen.

No error is raised and the JA3 token is parsed & spoofed successfully

To Reproduce Steps to reproduce the behavior

const fetch = require('node-fetch')
const initCycleTLS = require('cycletls')

async function start () {
  const fetchResp = await fetch('https://ja3er.com/json')
  const ja3 = (await fetchResp.json()).ja3
  // ja3 = "771,4866-4867-4865-49199-49195-49200-49196-158-49191-103-49192-107-163-159-52393-52392-52394-49327-49325-49315-49311-49245-49249-49239-49235-162-49326-49324-49314-49310-49244-49248-49238-49234-49188-106-49187-64-49162-49172-57-56-49161-49171-51-50-157-49313-49309-49233-156-49312-49308-49232-61-60-53-47-255,0-11-10-35-22-23-13-43-45-51,29-23-1035-25-24,0-1-2"

  const cycleTLS = await initCycleTLS()
  const response = await cycleTLS('https://ja3er.com/json', {
    ja3,
    userAgent: 'node-fetch/1.0 (+https://github.com/bitinn/node-fetch)',
  }, 'get')

  console.log(response)

  cycleTLS.exit()
}

start()

Additional Information

I also want to mention that in addition to the above this library seems to strain my CPU (5950X) quite a lot for some reason.

const initCycleTLS = require('cycletls')

async function start () {
  // await initCycleTLS()

  while (true) {
    await new Promise(resolve => setTimeout(resolve, 2000))
    console.log('sleep')
  }
}

start()

Uncommenting the initCycleTLS() bumps my CPU from 50c to 75c, I'm not sure if this is because of the Golang process it spawns, but it does seem excessive? mytls library does not appear to have this issue, CPU remains the same, no additional load.

Example:

  • Operating System information (e.g. Ubuntu 18.04): Windows 10 @ [email protected]
  • Node version: v15.12.0
  • Golang version: Golang isn't installed

Https URLS not working

Actual behavior The HTTPS client has a memory issue and breaks the worker pool that runs in the background

Expected behavior client functions the same as the HTTP client
To Reproduce Steps to reproduce the behavior

  1. put HTTPS in the request header

Additional Information
Working on fixes

Getting 403 with Golang package but works fine with node

Description

Hi, I came across with a weird thing. The spoof works fine with node js but when I try the same in Golang package I get 403. Not sure why.
I can send you the code for this "IF needed"
but this is so strange

Issue Type

Bug

Operating System

Mac OS

Node Version

Node 16.x

Golang Version

Go 16.x

Relevant Log Output

No response

ARM64 support

Hi, I can build the binary file for Linux ARM64 with flag GOARCH=arm64, but it doesn't seem to work. Keeps getting this error listen tcp :9119: bind: address already in use

Is there any plan to support ARM64?

Headers are not being applied

Actual behavior

Headers specified in cycletls.Options are not applied using the Go library.

Expected behavior

https://httpbin.org/headers should return the additional header (foo)

To Reproduce Steps to reproduce the behavior

r, err := client.Do("https://httpbin.org/headers", cycletls.Options{
		Ja3:       fp.Ja3,
		UserAgent: fp.UserAgent,
		Headers:   map[string]string{
                     "foo": "bar",
                },
	}, opts.Method)

Additional Information

  • Operating System information: Darwin Big Sur 11.6
  • Node version: N/A
  • Golang version: go1.17.6 darwin/arm64

go.mod

github.com/Danny-Dasilva/CycleTLS/cycletls v0.0.0-20220211211237-3f5cc5690340 // indirect
github.com/Danny-Dasilva/fhttp v0.0.0-20211010093114-56fde831fe2f // indirect

Memory Leak on Exit

Actual behavior
Cycle TLS spawns two PIDs when creating the golang process that needs to be exited cleanly both on SIGTERM and on cycleTLS.exit(). Windows handles this spawned process differently so Unix based system kills do not work.

Expected behavior A clear and concise description of what you expected to
happen.

To Reproduce Steps to reproduce the behavior

  1. ps -ef | grep index or a similar golang file when calling cycleTLS.exit()
  2. This issue on windows
  • Operating System information (e.g. Ubuntu 18.04): Windows/Max/Linux

Socket error when using CycleTLS

I open and close the connection after every request as instructed in documentation but after a few requests this error is thrown:

2021-08-24T13:04:58.761946+00:00 app[worker.1]: 2021/08/24 13:04:58 Socket Errorwebsocket: close 1006 (abnormal closure): unexpected EOF
2021-08-24T13:04:58.761946+00:00 app[worker.1]: 2021/08/24 13:04:58 Socket Errorwebsocket: close 1006 (abnormal closure): unexpected EOF
2021-08-24T13:04:58.761947+00:00 app[worker.1]: 2021/08/24 13:04:58 Socket Errorwebsocket: close 1006 (abnormal closure): unexpected EOF
2021-08-24T13:04:58.761947+00:00 app[worker.1]: 2021/08/24 13:04:58 Socket Errorwebsocket: close 1006 (abnormal closure): unexpected EOF
2021-08-24T13:04:58.761947+00:00 app[worker.1]: 2021/08/24 13:04:58 Socket Errorwebsocket: close 1006 (abnormal closure): unexpected EOF
2021-08-24T13:04:58.761947+00:00 app[worker.1]: 2021/08/24 13:04:58 Socket Errorwebsocket: close 1006 (abnormal closure): unexpected EOF
2021-08-24T13:04:58.761947+00:00 app[worker.1]: 
2021-08-24T13:04:58.761948+00:00 app[worker.1]:     at Socket.<anonymous> (/app/node_modules/cycletls/dist/index.js:67:33)
2021-08-24T13:04:58.761948+00:00 app[worker.1]:     at Socket.emit (node:events:394:28)
2021-08-24T13:04:58.761949+00:00 app[worker.1]:     at addChunk (node:internal/streams/readable:312:12)
2021-08-24T13:04:58.761949+00:00 app[worker.1]:     at readableAddChunk (node:internal/streams/readable:287:9)
2021-08-24T13:04:58.761949+00:00 app[worker.1]:     at Socket.Readable.push (node:internal/streams/readable:226:10)
2021-08-24T13:04:58.761950+00:00 app[worker.1]:     at Pipe.onStreamRead (node:internal/stream_base_commons:190:23)

I'm sending a requesting every 10 seconds and I make sure to close the connection after every request.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    πŸ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. πŸ“ŠπŸ“ˆπŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❀️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.