From 15fd7186acdc4ecc5f38f8db104fb1c2b5cd03d5 Mon Sep 17 00:00:00 2001 From: lwthiker Date: Sun, 10 Apr 2022 18:21:45 +0300 Subject: [PATCH 01/15] Add Makefile to orchestrate native builds Add a Makefile to orchestrate native builds of curl-impersonate without Docker. The Makefile does not compile any program by itself but is just used to build all the dependencies and then build curl itself with the needed patches. It has a very similar flow to the Dockerfile. --- Makefile | 215 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 215 insertions(+) create mode 100644 Makefile diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..25d97d8 --- /dev/null +++ b/Makefile @@ -0,0 +1,215 @@ +# Makefile to build curl-impersonate +# Some Makefile tricks were taken from https://tech.davis-hansson.com/p/make/ + +SHELL := bash +.ONESHELL: +.SHELLFLAGS := -eu -o pipefail -c +.DELETE_ON_ERROR: +MAKEFLAGS += --warn-undefined-variables +MAKEFLAGS += --no-builtin-rules + +BROTLI_VERSION := 1.0.9 +NSS_VERSION := nss-3.75 +NSS_URL := https://ftp.mozilla.org/pub/security/nss/releases/NSS_3_75_RTM/src/nss-3.75-with-nspr-4.32.tar.gz +BORING_SSL_COMMIT := 3a667d10e94186fd503966f5638e134fe9fb4080 +NGHTTP2_VERSION := nghttp2-1.46.0 +NGHTTP2_URL := https://github.com/nghttp2/nghttp2/releases/download/v1.46.0/nghttp2-1.46.0.tar.bz2 +CURL_VERSION := curl-7.81.0 + +brotli_install_dir := $(abspath brotli-$(BROTLI_VERSION)/out/installed) +brotli_static_libs := $(brotli_install_dir)/lib/libbrotlicommon-static.a $(brotli_install_dir)/lib/libbrotlidec-static.a +nss_install_dir := $(abspath $(NSS_VERSION)/dist/Release) +nss_static_libs := $(nss_install_dir)/lib/libnss_static.a +boringssl_install_dir := $(abspath boringssl/build) +boringssl_static_libs := $(boringssl_install_dir)/lib/libssl.a $(boringssl_install_dir)/lib/libcrypto.a +nghttp2_install_dir := $(abspath $(NGHTTP2_VERSION)/installed) +nghttp2_static_libs := $(nghttp2_install_dir)/lib/libnghttp2.a + +# Dependencies needed to compile the Firefox version +firefox_libs := $(brotli_static_libs) $(nss_static_libs) $(nghttp2_static_libs) +# Dependencies needed to compile the Chrome version +chrome_libs := $(brotli_static_libs) $(boringssl_static_libs) $(nghttp2_static_libs) + +basedir := $(shell dirname $(realpath $(firstword $(MAKEFILE_LIST)))) + +# Auto-generate Makefile help. +# Borrowed from https://marmelab.com/blog/2016/02/29/auto-documented-makefile.html +help: ## Show this help message + @grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}' +.PHONY: help +.DEFAULT_GOAL := help + +firefox: curl-impersonate-ff ## Build the Firefox version of curl-impersonate +.PHONY: firefox + +chrome: curl-impersonate-chrome ## Build the Chrome version of curl-impersonate +.PHONY: chrome + +clean: ## Remove build artifacts + rm -Rf brotli-$(BROTLI_VERSION).tar.gz brotli-$(BROTLI_VERSION) + rm -Rf $(NSS_VERSION).tar.gz $(NSS_VERSION) + rm -Rf boringssl.zip boringssl + rm -Rf $(NGHTTP2_VERSION).tar.bz2 $(NGHTTP2_VERSION) + rm -Rf $(CURL_VERSION).tar.xz $(CURL_VERSION) + rm -Rf out + +brotli-$(BROTLI_VERSION).tar.gz: + curl -L "https://github.com/google/brotli/archive/refs/tags/v${BROTLI_VERSION}.tar.gz" \ + -o "brotli-${BROTLI_VERSION}.tar.gz" + +$(brotli_static_libs): brotli-$(BROTLI_VERSION).tar.gz + tar xf brotli-$(BROTLI_VERSION).tar.gz + cd brotli-$(BROTLI_VERSION) + mkdir -p out + cd out + cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=./installed .. + cmake --build . --config Release --target install + + +$(NSS_VERSION).tar.gz: + curl -L -o $(NSS_VERSION).tar.gz $(NSS_URL) + +$(nss_static_libs): $(NSS_VERSION).tar.gz + tar xf $(NSS_VERSION).tar.gz + cd $(NSS_VERSION)/nss + ./build.sh -o --disable-tests --static + + +boringssl.zip: + curl -L https://github.com/google/boringssl/archive/$(BORING_SSL_COMMIT).zip \ + -o boringssl.zip + +# Patch boringssl and use a dummy '.patched' file to mark it patched +boringssl/.patched: $(basedir)/chrome/patches/boringssl-*.patch + unzip -o boringssl.zip + mv boringssl-$(BORING_SSL_COMMIT) boringssl + cd boringssl/ + for p in $^; do patch -p1 < $$p; done + touch .patched + +$(boringssl_static_libs): boringssl.zip boringssl/.patched + mkdir -p $(boringssl_install_dir) + cd $(boringssl_install_dir) + cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_POSITION_INDEPENDENT_CODE=on -GNinja .. + ninja + # Fix the directory structure so that curl can compile against it. + # See https://everything.curl.dev/source/build/tls/boringssl + mkdir -p lib + ln -sf ../crypto/libcrypto.a lib/libcrypto.a + ln -sf ../ssl/libssl.a lib/libssl.a + cp -Rf ../include . + + +$(NGHTTP2_VERSION).tar.bz2: + curl -L $(NGHTTP2_URL) -o $(NGHTTP2_VERSION).tar.bz2 + +# Patch nghttp2 and use a dummy '.patched' file to mark it patched +$(NGHTTP2_VERSION)/.patched: $(basedir)/firefox/patches/libnghttp2-*.patch + rm -Rf $(NGHTTP2_VERSION) + tar -xf $(NGHTTP2_VERSION).tar.bz2 + cd $(NGHTTP2_VERSION) + for p in $^; do patch -p1 < $$p; done + # Re-generate the configure script + autoreconf -i && automake && autoconf + touch .patched + +$(nghttp2_static_libs): $(NGHTTP2_VERSION).tar.bz2 $(NGHTTP2_VERSION)/.patched + cd $(NGHTTP2_VERSION) + ./configure --prefix=$(nghttp2_install_dir) --with-pic + make MAKEFLAGS= + make install MAKEFLAGS= + +$(CURL_VERSION).tar.xz: + curl -L "https://curl.se/download/$(CURL_VERSION).tar.xz" \ + -o "$(CURL_VERSION).tar.xz" + +# Apply the "Firefox version" patches and mark using a dummy file +$(CURL_VERSION)/.patched-ff: $(basedir)/firefox/patches/curl-*.patch + rm -Rf $(CURL_VERSION) + tar -xf $(CURL_VERSION).tar.xz + cd $(CURL_VERSION) + for p in $^; do patch -p1 < $$p; done + # Re-generate the configure script + autoreconf -fi + touch .patched-ff + rm -f .patched-chrome + +# Apply the "Chorme version" patches and mark using a dummy file +$(CURL_VERSION)/.patched-chrome: $(basedir)/chrome/patches/curl-*.patch + rm -Rf $(CURL_VERSION) + tar -xf $(CURL_VERSION).tar.xz + cd $(CURL_VERSION) + for p in $^; do patch -p1 < $$p; done + # Re-generate the configure script + autoreconf -fi + touch .patched-chrome + rm -f .patched-ff + +# This is a small hack that flags that curl was patched and configured in the "firefox" version +$(CURL_VERSION)/.firefox: $(firefox_libs) $(CURL_VERSION).tar.xz $(CURL_VERSION)/.patched-ff + cd $(CURL_VERSION) + ./configure --enable-static \ + --disable-shared \ + --with-zlib \ + --with-nghttp2=$(nghttp2_install_dir) \ + --with-brotli=$(brotli_install_dir) \ + --with-nss=$(nss_install_dir) \ + USE_CURL_SSLKEYLOGFILE=true \ + CFLAGS="-I$(nss_install_dir)/../public/nss -I$(nss_install_dir)/include/nspr" + # Remove possible leftovers from a previous compilation + make clean MAKEFLAGS= + touch .firefox + # Remove the Chrome flag if it exists + rm -f .chrome + +# This is a small hack that flags that curl was patched and configured in the "chrome" version +$(CURL_VERSION)/.chrome: $(chrome_libs) $(CURL_VERSION).tar.xz $(CURL_VERSION)/.patched-chrome + cd $(CURL_VERSION) + ./configure --enable-static \ + --disable-shared \ + --with-zlib \ + --with-nghttp2=$(nghttp2_install_dir) \ + --with-brotli=$(brotli_install_dir) \ + --with-openssl=$(boringssl_install_dir) \ + USE_CURL_SSLKEYLOGFILE=true \ + LIBS="-pthread" \ + CFLAGS="-I$(boringssl_install_dir)" + # Remove possible leftovers from a previous compilation + make clean MAKEFLAGS= + touch .chrome + # Remove the Firefox flag if it exists + rm -f .firefox + + +out/curl-impersonate-ff: $(CURL_VERSION)/.firefox + cd $(CURL_VERSION) + make MAKEFLAGS= + cd $(CURDIR) + mkdir -p $(@D) + cp -f $(CURL_VERSION)/src/curl $@ + strip $@ + +# Wrapper scripts for the Firefox version (e.g. 'curl_ff98') +ff-wrappers: + cp -f $(basedir)/firefox/curl_ff* out/ +.PHONY: ff-wrappers + +curl-impersonate-ff: out/curl-impersonate-ff ff-wrappers +.PHONY: curl-impersonate-ff + + +out/curl-impersonate-chrome: $(CURL_VERSION)/.chrome + cd $(CURL_VERSION) + make MAKEFLAGS= + cd $(CURDIR) + mkdir -p $(@D) + cp -f $(CURL_VERSION)/src/curl $@ + strip $@ + +# Wrapper scripts for the Chrome version (e.g. 'curl_chrome99') +chrome-wrappers: + cp -f $(basedir)/chrome/curl_chrome* $(basedir)/chrome/curl_edge* $(basedir)/chrome/curl_safari* out/ +.PHONY: chrome-wrappers + +curl-impersonate-chrome: out/curl-impersonate-chrome chrome-wrappers +.PHONY: curl-impersonate-chrome From 35623ee453cee957c3502ea4132fb5935faaa188 Mon Sep 17 00:00:00 2001 From: lwthiker Date: Mon, 11 Apr 2022 14:06:59 +0300 Subject: [PATCH 02/15] Use autoconf to configure the Makefile Use a 'configure' script generated by autoconf to configure whether a static build is desired, and where to install the final curl-impersonate binaries. Add installation targets to the Makefile. --- Makefile => Makefile.in | 75 +++++++++++++++++------------------------ configure.ac | 11 ++++++ 2 files changed, 42 insertions(+), 44 deletions(-) rename Makefile => Makefile.in (85%) create mode 100644 configure.ac diff --git a/Makefile b/Makefile.in similarity index 85% rename from Makefile rename to Makefile.in index 25d97d8..f8675b7 100644 --- a/Makefile +++ b/Makefile.in @@ -32,6 +32,10 @@ chrome_libs := $(brotli_static_libs) $(boringssl_static_libs) $(nghttp2_static_l basedir := $(shell dirname $(realpath $(firstword $(MAKEFILE_LIST)))) +# To be set by the configure script +prefix = @prefix@ +exec_prefix = @exec_prefix@ + # Auto-generate Makefile help. # Borrowed from https://marmelab.com/blog/2016/02/29/auto-documented-makefile.html help: ## Show this help message @@ -39,19 +43,38 @@ help: ## Show this help message .PHONY: help .DEFAULT_GOAL := help -firefox: curl-impersonate-ff ## Build the Firefox version of curl-impersonate +firefox-build: $(CURL_VERSION)/.firefox ## Build the Firefox version of curl-impersonate + cd $(CURL_VERSION) + # Don't pass this Makefile's MAKEFLAGS + make MAKEFLAGS= .PHONY: firefox -chrome: curl-impersonate-chrome ## Build the Chrome version of curl-impersonate +firefox-install: ## Install the Firefox version of curl-impersonate after build + cd $(CURL_VERSION) + make install MAKEFLAGS= + # Wrapper scripts for the Firefox version (e.g. 'curl_ff98') + cp -f $(basedir)/firefox/curl_ff* @bindir@ +.PHONY: firefox-install + +chrome-build: $(CURL_VERSION)/.chrome ## Build the Chrome version of curl-impersonate + cd $(CURL_VERSION) + # Don't pass this Makefile's MAKEFLAGS + make MAKEFLAGS= .PHONY: chrome -clean: ## Remove build artifacts +chrome-install: ## Install the Chrome version of curl-impersonate after build + cd $(CURL_VERSION) + make install MAKEFLAGS= + # Wrapper scripts for the Chrome version (e.g. 'curl_chrome99') + cp -f $(basedir)/chrome/curl_chrome* $(basedir)/chrome/curl_edge* $(basedir)/chrome/curl_safari* @bindir@ +.PHONY: chrome-install + +clean: ## Remove all build artifacts rm -Rf brotli-$(BROTLI_VERSION).tar.gz brotli-$(BROTLI_VERSION) rm -Rf $(NSS_VERSION).tar.gz $(NSS_VERSION) rm -Rf boringssl.zip boringssl rm -Rf $(NGHTTP2_VERSION).tar.bz2 $(NGHTTP2_VERSION) rm -Rf $(CURL_VERSION).tar.xz $(CURL_VERSION) - rm -Rf out brotli-$(BROTLI_VERSION).tar.gz: curl -L "https://github.com/google/brotli/archive/refs/tags/v${BROTLI_VERSION}.tar.gz" \ @@ -148,9 +171,8 @@ $(CURL_VERSION)/.patched-chrome: $(basedir)/chrome/patches/curl-*.patch # This is a small hack that flags that curl was patched and configured in the "firefox" version $(CURL_VERSION)/.firefox: $(firefox_libs) $(CURL_VERSION).tar.xz $(CURL_VERSION)/.patched-ff cd $(CURL_VERSION) - ./configure --enable-static \ - --disable-shared \ - --with-zlib \ + ./configure @curl_configure_options@ \ + --prefix=@prefix@ \ --with-nghttp2=$(nghttp2_install_dir) \ --with-brotli=$(brotli_install_dir) \ --with-nss=$(nss_install_dir) \ @@ -165,9 +187,8 @@ $(CURL_VERSION)/.firefox: $(firefox_libs) $(CURL_VERSION).tar.xz $(CURL_VERSION) # This is a small hack that flags that curl was patched and configured in the "chrome" version $(CURL_VERSION)/.chrome: $(chrome_libs) $(CURL_VERSION).tar.xz $(CURL_VERSION)/.patched-chrome cd $(CURL_VERSION) - ./configure --enable-static \ - --disable-shared \ - --with-zlib \ + ./configure @curl_configure_options@ \ + --prefix=@prefix@ \ --with-nghttp2=$(nghttp2_install_dir) \ --with-brotli=$(brotli_install_dir) \ --with-openssl=$(boringssl_install_dir) \ @@ -179,37 +200,3 @@ $(CURL_VERSION)/.chrome: $(chrome_libs) $(CURL_VERSION).tar.xz $(CURL_VERSION)/. touch .chrome # Remove the Firefox flag if it exists rm -f .firefox - - -out/curl-impersonate-ff: $(CURL_VERSION)/.firefox - cd $(CURL_VERSION) - make MAKEFLAGS= - cd $(CURDIR) - mkdir -p $(@D) - cp -f $(CURL_VERSION)/src/curl $@ - strip $@ - -# Wrapper scripts for the Firefox version (e.g. 'curl_ff98') -ff-wrappers: - cp -f $(basedir)/firefox/curl_ff* out/ -.PHONY: ff-wrappers - -curl-impersonate-ff: out/curl-impersonate-ff ff-wrappers -.PHONY: curl-impersonate-ff - - -out/curl-impersonate-chrome: $(CURL_VERSION)/.chrome - cd $(CURL_VERSION) - make MAKEFLAGS= - cd $(CURDIR) - mkdir -p $(@D) - cp -f $(CURL_VERSION)/src/curl $@ - strip $@ - -# Wrapper scripts for the Chrome version (e.g. 'curl_chrome99') -chrome-wrappers: - cp -f $(basedir)/chrome/curl_chrome* $(basedir)/chrome/curl_edge* $(basedir)/chrome/curl_safari* out/ -.PHONY: chrome-wrappers - -curl-impersonate-chrome: out/curl-impersonate-chrome chrome-wrappers -.PHONY: curl-impersonate-chrome diff --git a/configure.ac b/configure.ac new file mode 100644 index 0000000..d2279f5 --- /dev/null +++ b/configure.ac @@ -0,0 +1,11 @@ +AC_INIT([curl-impersonate], [0.3.2], [lwt@lwthiker.com]) + +AC_ARG_ENABLE([static], + [AS_HELP_STRING([--enable-static], + [Build curl-impersonate statically with libcurl-impersonate])], + [AC_SUBST([curl_configure_options], ["--enable-static --disable-shared"])], + []) + +AC_CONFIG_FILES([Makefile]) + +AC_OUTPUT From b484701491dbeb12fe69cbd5ec0d34e79a330d28 Mon Sep 17 00:00:00 2001 From: lwthiker Date: Tue, 12 Apr 2022 11:32:50 +0300 Subject: [PATCH 03/15] Use autoconf's srcdir variable in Makefile.in Use autoconf's automatic variable 'abs_srcdir' to find the path to the patch files and wrapper scripts, instead of relying on the Makefile's directory. This allows doing out-of-tree builds, i.e. 'mkdir build && cd build && ../configure && make'. --- Makefile.in | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/Makefile.in b/Makefile.in index f8675b7..853c3de 100644 --- a/Makefile.in +++ b/Makefile.in @@ -30,11 +30,10 @@ firefox_libs := $(brotli_static_libs) $(nss_static_libs) $(nghttp2_static_libs) # Dependencies needed to compile the Chrome version chrome_libs := $(brotli_static_libs) $(boringssl_static_libs) $(nghttp2_static_libs) -basedir := $(shell dirname $(realpath $(firstword $(MAKEFILE_LIST)))) - # To be set by the configure script prefix = @prefix@ exec_prefix = @exec_prefix@ +srcdir = @abs_srcdir@ # Auto-generate Makefile help. # Borrowed from https://marmelab.com/blog/2016/02/29/auto-documented-makefile.html @@ -53,7 +52,7 @@ firefox-install: ## Install the Firefox version of curl-impersonate after build cd $(CURL_VERSION) make install MAKEFLAGS= # Wrapper scripts for the Firefox version (e.g. 'curl_ff98') - cp -f $(basedir)/firefox/curl_ff* @bindir@ + cp -f $(srcdir)/firefox/curl_ff* @bindir@ .PHONY: firefox-install chrome-build: $(CURL_VERSION)/.chrome ## Build the Chrome version of curl-impersonate @@ -66,7 +65,7 @@ chrome-install: ## Install the Chrome version of curl-impersonate after build cd $(CURL_VERSION) make install MAKEFLAGS= # Wrapper scripts for the Chrome version (e.g. 'curl_chrome99') - cp -f $(basedir)/chrome/curl_chrome* $(basedir)/chrome/curl_edge* $(basedir)/chrome/curl_safari* @bindir@ + cp -f $(srcdir)/chrome/curl_chrome* $(srcdir)/chrome/curl_edge* $(srcdir)/chrome/curl_safari* @bindir@ .PHONY: chrome-install clean: ## Remove all build artifacts @@ -103,7 +102,7 @@ boringssl.zip: -o boringssl.zip # Patch boringssl and use a dummy '.patched' file to mark it patched -boringssl/.patched: $(basedir)/chrome/patches/boringssl-*.patch +boringssl/.patched: $(srcdir)/chrome/patches/boringssl-*.patch unzip -o boringssl.zip mv boringssl-$(BORING_SSL_COMMIT) boringssl cd boringssl/ @@ -127,7 +126,7 @@ $(NGHTTP2_VERSION).tar.bz2: curl -L $(NGHTTP2_URL) -o $(NGHTTP2_VERSION).tar.bz2 # Patch nghttp2 and use a dummy '.patched' file to mark it patched -$(NGHTTP2_VERSION)/.patched: $(basedir)/firefox/patches/libnghttp2-*.patch +$(NGHTTP2_VERSION)/.patched: $(srcdir)/firefox/patches/libnghttp2-*.patch rm -Rf $(NGHTTP2_VERSION) tar -xf $(NGHTTP2_VERSION).tar.bz2 cd $(NGHTTP2_VERSION) @@ -147,7 +146,7 @@ $(CURL_VERSION).tar.xz: -o "$(CURL_VERSION).tar.xz" # Apply the "Firefox version" patches and mark using a dummy file -$(CURL_VERSION)/.patched-ff: $(basedir)/firefox/patches/curl-*.patch +$(CURL_VERSION)/.patched-ff: $(srcdir)/firefox/patches/curl-*.patch rm -Rf $(CURL_VERSION) tar -xf $(CURL_VERSION).tar.xz cd $(CURL_VERSION) @@ -158,7 +157,7 @@ $(CURL_VERSION)/.patched-ff: $(basedir)/firefox/patches/curl-*.patch rm -f .patched-chrome # Apply the "Chorme version" patches and mark using a dummy file -$(CURL_VERSION)/.patched-chrome: $(basedir)/chrome/patches/curl-*.patch +$(CURL_VERSION)/.patched-chrome: $(srcdir)/chrome/patches/curl-*.patch rm -Rf $(CURL_VERSION) tar -xf $(CURL_VERSION).tar.xz cd $(CURL_VERSION) From 7e19dd72214e9458b4a3feb8e87ffd374322803a Mon Sep 17 00:00:00 2001 From: lwthiker Date: Tue, 12 Apr 2022 11:34:20 +0300 Subject: [PATCH 04/15] Only install binaries in 'make install' When doing 'make firefox-install' or 'make chrome-install' in our own Makefile, only install curl's binaries (curl & libcurl) and do not install the man pages and headers. This will prevent collision of these files with any installed curl man pages or headers. In the future it might be possible to rename the man pages or headers as well to allow them live side-by-side with the vanilla curl. --- Makefile.in | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Makefile.in b/Makefile.in index 853c3de..cc26187 100644 --- a/Makefile.in +++ b/Makefile.in @@ -50,7 +50,7 @@ firefox-build: $(CURL_VERSION)/.firefox ## Build the Firefox version of curl-imp firefox-install: ## Install the Firefox version of curl-impersonate after build cd $(CURL_VERSION) - make install MAKEFLAGS= + make install-exec MAKEFLAGS= # Wrapper scripts for the Firefox version (e.g. 'curl_ff98') cp -f $(srcdir)/firefox/curl_ff* @bindir@ .PHONY: firefox-install @@ -63,7 +63,7 @@ chrome-build: $(CURL_VERSION)/.chrome ## Build the Chrome version of curl-impers chrome-install: ## Install the Chrome version of curl-impersonate after build cd $(CURL_VERSION) - make install MAKEFLAGS= + make install-exec MAKEFLAGS= # Wrapper scripts for the Chrome version (e.g. 'curl_chrome99') cp -f $(srcdir)/chrome/curl_chrome* $(srcdir)/chrome/curl_edge* $(srcdir)/chrome/curl_safari* @bindir@ .PHONY: chrome-install From 4e102d1fbfdbd8837c385cf50518205d94cf1af1 Mon Sep 17 00:00:00 2001 From: lwthiker Date: Tue, 12 Apr 2022 11:36:13 +0300 Subject: [PATCH 05/15] Add Makefile uninstall targets Add two targets for uninstalling curl-impersonate to the Makefile. --- Makefile.in | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/Makefile.in b/Makefile.in index cc26187..465523d 100644 --- a/Makefile.in +++ b/Makefile.in @@ -55,6 +55,12 @@ firefox-install: ## Install the Firefox version of curl-impersonate after build cp -f $(srcdir)/firefox/curl_ff* @bindir@ .PHONY: firefox-install +firefox-uninstall: ## Uninstall the Firefox version of curl-impersonate after 'make install' + cd $(CURL_VERSION) + make uninstall MAKEFLAGS= + rm -Rf @bindir@/curl_ff* +.PHONY: firefox-uninstall + chrome-build: $(CURL_VERSION)/.chrome ## Build the Chrome version of curl-impersonate cd $(CURL_VERSION) # Don't pass this Makefile's MAKEFLAGS @@ -68,7 +74,13 @@ chrome-install: ## Install the Chrome version of curl-impersonate after build cp -f $(srcdir)/chrome/curl_chrome* $(srcdir)/chrome/curl_edge* $(srcdir)/chrome/curl_safari* @bindir@ .PHONY: chrome-install -clean: ## Remove all build artifacts +chrome-uninstall: ## Uninstall the Chrome version of curl-impersonate after 'make install' + cd $(CURL_VERSION) + make uninstall MAKEFLAGS= + rm -Rf @bindir@/curl_chrome* @bindir@/curl_edge* @bindir@/curl_safari* +.PHONY: chrome-uninstall + +clean: ## Remove build artifacts rm -Rf brotli-$(BROTLI_VERSION).tar.gz brotli-$(BROTLI_VERSION) rm -Rf $(NSS_VERSION).tar.gz $(NSS_VERSION) rm -Rf boringssl.zip boringssl From 493576a15eee2ce15872d0ccf75751f1b6fd020c Mon Sep 17 00:00:00 2001 From: lwthiker Date: Tue, 12 Apr 2022 12:28:07 +0300 Subject: [PATCH 06/15] Add INSTALL.md Add INSTALL.md with explanation about using the new Makefile-based build system and the Docker-based build system, and remove the same section from README.md. --- INSTALL.md | 92 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ README.md | 31 ++---------------- 2 files changed, 95 insertions(+), 28 deletions(-) create mode 100644 INSTALL.md diff --git a/INSTALL.md b/INSTALL.md new file mode 100644 index 0000000..7015818 --- /dev/null +++ b/INSTALL.md @@ -0,0 +1,92 @@ +# Building and installing curl-impersonate + +This guide shows how to compile and install curl-impersonate and libcurl-impersonate from source. +The build process takes care of downloading dependencies, patching them, compiling them and finally compiling curl itself with the needed patches. +There are currently two build options depending on your use case: +* Native build using Makefile +* Docker container build + +There are two versions of `curl-impersonate` for technical reasons. The **chrome** version is used to impersonate Chrome, Edge and Safari. The **firefox** version is used to impersonate Firefox. + +## Native build +Currently tested for Linux only. Work on porting to Mac is in progress. + +Install dependencies for building all the components: +``` +sudo apt install build-essential pkg-config cmake ninja-build curl autoconf automake libtool +# For the Firefox version only +sudo apt install python3-pip python-is-python3 +pip install gyp-next +# For the Chrome vesion only +sudo apt install golang-go +``` + +Clone this repository: +``` +git clone https://github.com/lwthiker/curl-impersonate.git +cd curl-impersonate +``` + +Generate the configure script: +``` +autoconf +``` + +Configure and compile: +``` +mkdir build && cd build +../configure +# Build and install the Firefox version +make firefox-build +make firefox-install +# Build and install the Chrome version +make chrome-build +make chrome-install +# Optionally remove all the build files +cd ../ && rm -Rf build +``` + +This will install curl-impersonate, libcurl-impersonate and the wrapper scripts to `/usr/local`. To change the installation path, pass `--prefix=/path/to/install/` to the `configure` script. + +After installation you can run the wrapper scripts, e.g.: +``` +curl_ff98 https://www.wikipedia.org +curl_chrome99 https://www.wikipedia.org +``` + +or run directly with you own flags: +``` +curl-impersonate-ff https://www.wikipedia.org +curl-impersonate-chrome https://www.wikipedia.org +``` + +### Static compilation +To compile curl-impersonate statically with libcurl-impersonate, pass `--enable-static` to the `configure` script. + +## Docker build +The Docker build is a bit more reproducible and serves as the reference implementation. It creates a Debian-based Docker image with the binaries. + +### Chrome version +[`chrome/Dockerfile`](chrome/Dockerfile) is a debian-based Dockerfile that will build curl with all the necessary modifications and patches. Build it like the following: +``` +docker build -t curl-impersonate-chrome chrome/ +``` +The resulting image contains a `/build/out` directory with the following: +* `curl-impersonate-chrome`, `curl-impersonate` - The curl binary that can impersonate Chrome/Edge/Safari. It is compiled statically against libcurl, BoringSSL, and libnghttp2 so that it won't conflict with any existing libraries on your system. You can use it from the container or copy it out. Tested to work on Ubuntu 20.04. +* `curl_chrome98`, `curl_chrome99`, `...` - Wrapper scripts that launch `curl-impersonate` with all the needed flags. +* `libcurl-impersonate-chrome.so`, `libcurl-impersonate.so` - libcurl compiled with impersonation support. See [libcurl-impersonate](#libcurl-impersonate) below for more details. + +You can use them inside the docker, copy them out using `docker cp` or use them in a multi-stage docker build. + +### Firefox version +Build with: +``` +docker build -t curl-impersonate-ff firefox/ +``` +The resulting image contains a `/build/out` directory with the following: +* `curl-impersonate-ff`, `curl-impersonate` - The curl binary that can impersonate Firefox. It is compiled statically against libcurl, nss, and libnghttp2 so that it won't conflict with any existing libraries on your system. You can use it from the container or copy it out. Tested to work on Ubuntu 20.04. +* `curl_ff91esr`, `curl_ff95`, `...` - Wrapper scripts that launch `curl-impersonate` with all the needed flags. +* `libcurl-impersonate-ff.so`, `libcurl-impersonate.so` - libcurl compiled with impersonation support. See [libcurl-impersonate](#libcurl-impersonate) below for more details. + +If you use it outside the container, install the following dependency: +* `sudo apt install libnss3`. Even though nss is statically compiled into `curl-impersonate`, it is still necessary to install libnss3 because curl dynamically loads `libnssckbi.so`, a file containing Mozilla's list of trusted root certificates. Alternatively, use `curl -k` to disable certificate verification. diff --git a/README.md b/README.md index 23399f0..04aa055 100644 --- a/README.md +++ b/README.md @@ -49,6 +49,9 @@ See [Advanced usage](#Advanced-usage) for more options. ## Installation There are two versions of `curl-impersonate` for technical reasons. The **chrome** version is used to impersonate Chrome, Edge and Safari. The **firefox** version is used to impersonate Firefox. +### Building from source +See [INSTALL.md](INSTALL.md). + ### Docker images Docker images based on Alpine Linux with `curl-impersonate` compiled and ready to use are available on [Docker Hub](https://hub.docker.com/r/lwthiker/curl-impersonate). The images contain the binary and all the wrapper scripts. Use like the following: ```bash @@ -65,34 +68,6 @@ docker run --rm lwthiker/curl-impersonate:0.3-chrome curl_chrome99 https://www.w AUR packages are available to Arch users: [curl-impersonate-chrome](https://aur.archlinux.org/packages/curl-impersonate-chrome), [curl-impersonate-firefox](https://aur.archlinux.org/packages/curl-impersonate-firefox). -## Building from source -As mentioned there are two separate build systems. The **chrome** build is used to impersonate Chrome, Edge and Safari. The **firefox** build is used to impersonate Firefox. - -### Chrome build -[`chrome/Dockerfile`](chrome/Dockerfile) is a debian-based Dockerfile that will build curl with all the necessary modifications and patches. Build it like the following: -``` -docker build -t curl-impersonate-chrome chrome/ -``` -The resulting image contains a `/build/out` directory with the following: -* `curl-impersonate-chrome`, `curl-impersonate` - The curl binary that can impersonate Chrome/Edge/Safari. It is compiled statically against libcurl, BoringSSL, and libnghttp2 so that it won't conflict with any existing libraries on your system. You can use it from the container or copy it out. Tested to work on Ubuntu 20.04. -* `curl_chrome98`, `curl_chrome99`, `...` - Wrapper scripts that launch `curl-impersonate` with all the needed flags. -* `libcurl-impersonate-chrome.so`, `libcurl-impersonate.so` - libcurl compiled with impersonation support. See [libcurl-impersonate](#libcurl-impersonate) below for more details. - -You can use them inside the docker, copy them out using `docker cp` or use them in a multi-stage docker build. - -### Firefox build -Build with: -``` -docker build -t curl-impersonate-ff firefox/ -``` -The resulting image contains a `/build/out` directory with the following: -* `curl-impersonate-ff`, `curl-impersonate` - The curl binary that can impersonate Firefox. It is compiled statically against libcurl, nss, and libnghttp2 so that it won't conflict with any existing libraries on your system. You can use it from the container or copy it out. Tested to work on Ubuntu 20.04. -* `curl_ff91esr`, `curl_ff95`, `...` - Wrapper scripts that launch `curl-impersonate` with all the needed flags. -* `libcurl-impersonate-ff.so`, `libcurl-impersonate.so` - libcurl compiled with impersonation support. See [libcurl-impersonate](#libcurl-impersonate) below for more details. - -If you use it outside the container, install the following dependency: -* `sudo apt install libnss3`. Even though nss is statically compiled into `curl-impersonate`, it is still necessary to install libnss3 because curl dynamically loads `libnssckbi.so`, a file containing Mozilla's list of trusted root certificates. Alternatively, use `curl -k` to disable certificate verification. - ## Advanced usage ### libcurl-impersonate `libcurl-impersonate.so` is libcurl compiled with the same changes as the command line `curl-impersonate`. From 79f8601a309a2da3a963e29e521dcf1371ff89ac Mon Sep 17 00:00:00 2001 From: lwthiker Date: Tue, 12 Apr 2022 12:43:02 +0300 Subject: [PATCH 07/15] Fix typo in Makefile.in --- Makefile.in | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Makefile.in b/Makefile.in index 465523d..2ba2d3d 100644 --- a/Makefile.in +++ b/Makefile.in @@ -46,7 +46,7 @@ firefox-build: $(CURL_VERSION)/.firefox ## Build the Firefox version of curl-imp cd $(CURL_VERSION) # Don't pass this Makefile's MAKEFLAGS make MAKEFLAGS= -.PHONY: firefox +.PHONY: firefox-build firefox-install: ## Install the Firefox version of curl-impersonate after build cd $(CURL_VERSION) @@ -65,7 +65,7 @@ chrome-build: $(CURL_VERSION)/.chrome ## Build the Chrome version of curl-impers cd $(CURL_VERSION) # Don't pass this Makefile's MAKEFLAGS make MAKEFLAGS= -.PHONY: chrome +.PHONY: chrome-build chrome-install: ## Install the Chrome version of curl-impersonate after build cd $(CURL_VERSION) From facd6e55514fe1e912ebec47d568435321d32779 Mon Sep 17 00:00:00 2001 From: lwthiker Date: Tue, 12 Apr 2022 16:48:38 +0300 Subject: [PATCH 08/15] Use configurable binaries directory in the tests Locate curl-impersonate and libcurl-impersonate in a directory which is configurable from the command line instead of looking for them in the current directory. '--install-dir' is passed to pytest, where a 'bin' and 'lib' directories are expected with (lib)curl-impersonate. Rename the Actions file for the Docker build to allow the creation of addition Action for native builds. --- ...and-test.yml => build-and-test-docker.yml} | 4 +- README.md | 2 +- tests/Dockerfile | 12 ++- tests/conftest.py | 4 + tests/test_impersonate.py | 77 ++++++++++++------- 5 files changed, 63 insertions(+), 36 deletions(-) rename .github/workflows/{build-and-test.yml => build-and-test-docker.yml} (96%) create mode 100644 tests/conftest.py diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test-docker.yml similarity index 96% rename from .github/workflows/build-and-test.yml rename to .github/workflows/build-and-test-docker.yml index ac8d04b..accfc1a 100644 --- a/.github/workflows/build-and-test.yml +++ b/.github/workflows/build-and-test-docker.yml @@ -1,4 +1,4 @@ -name: Build and test +name: Docker images on: push: @@ -10,7 +10,7 @@ on: jobs: build-and-test: - name: Build curl-impersonate and run the tests + name: Build curl-impersonate Docker images and run the tests runs-on: ubuntu-latest services: # A local registry is needed to push the build images to because we use diff --git a/README.md b/README.md index 04aa055..bdcaacd 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# curl-impersonate · ![workflow](https://github.com/lwthiker/curl-impersonate/actions/workflows/build-and-test.yml/badge.svg) +# curl-impersonate · ![workflow](https://github.com/lwthiker/curl-impersonate/actions/workflows/build-and-test-docker.yml/badge.svg) A special compilation of [curl](https://github.com/curl/curl) that makes it impersonate real browsers. It can impersonate the four major browsers: Chrome, Edge, Safari & Firefox. This curl binary is able to perform a TLS handshake that is identical to that of a real browser. diff --git a/tests/Dockerfile b/tests/Dockerfile index d7b1801..e510d19 100644 --- a/tests/Dockerfile +++ b/tests/Dockerfile @@ -19,14 +19,18 @@ RUN pip install --upgrade pip && \ RUN mkdir /tests/firefox /tests/chrome # Copy the built binaries from both containers -COPY --from=ff /build/out/* /tests/firefox/ -COPY --from=chrome /build/out/* /tests/chrome/ +COPY --from=ff /build/out/curl-impersonate-ff /tests/install/bin/ +COPY --from=ff /build/out/curl_* /tests/install/bin/ +COPY --from=ff /build/out/libcurl-impersonate* /tests/install/lib/ +COPY --from=chrome /build/out/curl-impersonate-chrome /tests/install/bin/ +COPY --from=chrome /build/out/curl_* /tests/install/bin/ +COPY --from=chrome /build/out/libcurl-impersonate* /tests/install/lib/ COPY . . # Compile 'minicurl' which is used for testing libcurl-impersonate. # 'minicurl' is compiled against the "regular" libcurl. # libcurl-impersonate will replace it at runtime via LD_PRELOAD. -RUN gcc -Wall -Werror -o minicurl minicurl.c `curl-config --libs` +RUN gcc -Wall -Werror -o /tests/install/bin/minicurl minicurl.c `curl-config --libs` -ENTRYPOINT ["pytest"] +ENTRYPOINT ["pytest", "--install-dir", "/tests/install"] diff --git a/tests/conftest.py b/tests/conftest.py new file mode 100644 index 0000000..5428fa0 --- /dev/null +++ b/tests/conftest.py @@ -0,0 +1,4 @@ +def pytest_addoption(parser): + # Where to find curl-impersonate's binaries + parser.addoption("--install-dir", action="store", default="/usr/local") + parser.addoption("--capture-interface", action="store", default="eth0") diff --git a/tests/test_impersonate.py b/tests/test_impersonate.py index 1e0925a..9446b44 100644 --- a/tests/test_impersonate.py +++ b/tests/test_impersonate.py @@ -126,89 +126,89 @@ class TestImpersonation: # List of binaries and their expected signatures CURL_BINARIES_AND_SIGNATURES = [ # Test wrapper scripts - ("chrome/curl_chrome98", None, "chrome_98.0.4758.102_win10"), - ("chrome/curl_chrome99", None, "chrome_99.0.4844.51_win10"), - ("chrome/curl_chrome99_android", None, "chrome_99.0.4844.73_android12-pixel6"), - ("chrome/curl_edge98", None, "edge_98.0.1108.62_win10"), - ("chrome/curl_edge99", None, "edge_99.0.1150.30_win10"), - ("chrome/curl_safari15_3", None, "safari_15.3_macos11.6.4"), - ("firefox/curl_ff91esr", None, "firefox_91.6.0esr_win10"), - ("firefox/curl_ff95", None, "firefox_95.0.2_win10"), - ("firefox/curl_ff98", None, "firefox_98.0_win10"), + ("curl_chrome98", None, None, "chrome_98.0.4758.102_win10"), + ("curl_chrome99", None, None, "chrome_99.0.4844.51_win10"), + ("curl_chrome99_android", None, None, "chrome_99.0.4844.73_android12-pixel6"), + ("curl_edge98", None, None, "edge_98.0.1108.62_win10"), + ("curl_edge99", None, None, "edge_99.0.1150.30_win10"), + ("curl_safari15_3", None, None, "safari_15.3_macos11.6.4"), + ("curl_ff91esr", None, None, "firefox_91.6.0esr_win10"), + ("curl_ff95", None, None, "firefox_95.0.2_win10"), + ("curl_ff98", None, None, "firefox_98.0_win10"), # Test libcurl-impersonate by loading it with LD_PRELOAD to an app # linked against the regular libcurl and setting the # CURL_IMPERSONATE env var. ( - "./minicurl", + "minicurl", { - "LD_PRELOAD": "./chrome/libcurl-impersonate.so", "CURL_IMPERSONATE": "chrome98" }, + "libcurl-impersonate-chrome.so", "chrome_98.0.4758.102_win10" ), ( - "./minicurl", + "minicurl", { - "LD_PRELOAD": "./chrome/libcurl-impersonate.so", "CURL_IMPERSONATE": "chrome99" }, + "libcurl-impersonate-chrome.so", "chrome_99.0.4844.51_win10" ), ( - "./minicurl", + "minicurl", { - "LD_PRELOAD": "./chrome/libcurl-impersonate.so", "CURL_IMPERSONATE": "chrome99_android" }, + "libcurl-impersonate-chrome.so", "chrome_99.0.4844.73_android12-pixel6" ), ( - "./minicurl", + "minicurl", { - "LD_PRELOAD": "./chrome/libcurl-impersonate.so", "CURL_IMPERSONATE": "edge98" }, + "libcurl-impersonate-chrome.so", "edge_98.0.1108.62_win10" ), ( - "./minicurl", + "minicurl", { - "LD_PRELOAD": "./chrome/libcurl-impersonate.so", "CURL_IMPERSONATE": "edge99" }, + "libcurl-impersonate-chrome.so", "edge_99.0.1150.30_win10" ), ( - "./minicurl", + "minicurl", { - "LD_PRELOAD": "./chrome/libcurl-impersonate.so", "CURL_IMPERSONATE": "safari15_3" }, + "libcurl-impersonate-chrome.so", "safari_15.3_macos11.6.4" ), ( - "./minicurl", + "minicurl", { - "LD_PRELOAD": "./firefox/libcurl-impersonate.so", "CURL_IMPERSONATE": "ff91esr" }, + "libcurl-impersonate-ff.so", "firefox_91.6.0esr_win10" ), ( - "./minicurl", + "minicurl", { - "LD_PRELOAD": "./firefox/libcurl-impersonate.so", "CURL_IMPERSONATE": "ff95" }, + "libcurl-impersonate-ff.so", "firefox_95.0.2_win10" ), ( - "./minicurl", + "minicurl", { - "LD_PRELOAD": "./firefox/libcurl-impersonate.so", "CURL_IMPERSONATE": "ff98" }, + "libcurl-impersonate-ff.so", "firefox_98.0_win10" ) ] @@ -341,13 +341,15 @@ class TestImpersonation: return pseudo_headers, headers @pytest.mark.parametrize( - "curl_binary, env_vars, expected_signature", + "curl_binary, env_vars, ld_preload, expected_signature", CURL_BINARIES_AND_SIGNATURES ) def test_tls_client_hello(self, + pytestconfig, tcpdump, curl_binary, env_vars, + ld_preload, browser_signatures, expected_signature): """ @@ -358,6 +360,14 @@ class TestImpersonation: extracts the Client Hello packet from the capture and compares its signature with the expected one defined in the YAML database. """ + curl_binary = os.path.join( + pytestconfig.getoption("install_dir"), "bin", curl_binary + ) + if ld_preload: + env_vars["LD_PRELOAD"] = os.path.join( + pytestconfig.getoption("install_dir"), "lib", ld_preload + ) + ret = self._run_curl(curl_binary, env_vars=env_vars, extra_args=None, @@ -396,15 +406,24 @@ class TestImpersonation: assert equals, msg @pytest.mark.parametrize( - "curl_binary, env_vars, expected_signature", + "curl_binary, env_vars, ld_preload, expected_signature", CURL_BINARIES_AND_SIGNATURES ) def test_http2_headers(self, + pytestconfig, nghttpd, curl_binary, env_vars, + ld_preload, browser_signatures, expected_signature): + curl_binary = os.path.join( + pytestconfig.getoption("install_dir"), "bin", curl_binary + ) + if ld_preload: + env_vars["LD_PRELOAD"] = os.path.join( + pytestconfig.getoption("install_dir"), "lib", ld_preload + ) ret = self._run_curl(curl_binary, env_vars=env_vars, extra_args=["-k"], From f5467cec11a031d5478c233928befc1f39cfbed8 Mon Sep 17 00:00:00 2001 From: lwthiker Date: Tue, 12 Apr 2022 16:51:51 +0300 Subject: [PATCH 09/15] Use configurable tcpdump interface in the tests And add support for capturing the Client Hello message when sent over IPv6. --- tests/test_impersonate.py | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/tests/test_impersonate.py b/tests/test_impersonate.py index 9446b44..ffc4bbb 100644 --- a/tests/test_impersonate.py +++ b/tests/test_impersonate.py @@ -214,15 +214,17 @@ class TestImpersonation: ] @pytest.fixture - def tcpdump(self): + def tcpdump(self, pytestconfig): """Initialize a sniffer to capture curl's traffic.""" + interface = pytestconfig.getoption("capture_interface") + logging.debug( - f"Running tcpdump on interface {self.TCPDUMP_CAPTURE_INTERFACE}" + f"Running tcpdump on interface {interface}" ) p = subprocess.Popen([ "tcpdump", "-n", - "-i", self.TCPDUMP_CAPTURE_INTERFACE, + "-i", interface, "-s", "0", "-w", "-", "-U", # Important, makes tcpdump unbuffered @@ -282,7 +284,7 @@ class TestImpersonation: """ for ts, buf in dpkt.pcap.Reader(io.BytesIO(pcap)): eth = dpkt.ethernet.Ethernet(buf) - if not isinstance(eth.data, dpkt.ip.IP): + if not isinstance(eth.data, dpkt.ip.IP) and not isinstance(eth.data, dpkt.ip6.IP6): continue ip = eth.data if not isinstance(ip.data, dpkt.tcp.TCP): From 48d18cd8cdba3556e34a3d1d9e0141e4931d828a Mon Sep 17 00:00:00 2001 From: lwthiker Date: Tue, 12 Apr 2022 16:53:22 +0300 Subject: [PATCH 10/15] Add GitHub Action to test native builds Add a GitHub action to compile and test native builds using the new Makefile-based build system. Currently runs on Ubuntu and in the future will run similarly on MacOS. --- .github/workflows/build-and-test-make.yml | 62 +++++++++++++++++++++++ 1 file changed, 62 insertions(+) create mode 100644 .github/workflows/build-and-test-make.yml diff --git a/.github/workflows/build-and-test-make.yml b/.github/workflows/build-and-test-make.yml new file mode 100644 index 0000000..93f7ab4 --- /dev/null +++ b/.github/workflows/build-and-test-make.yml @@ -0,0 +1,62 @@ +name: Build and test + +on: + push: + branches: + - main + pull_request: + branches: + - main + +jobs: + build-and-test: + name: Build curl-impersonate and run the tests + runs-on: ${{ matrix.os }} + strategy: + matrix: + os: [ubuntu-20.04] + steps: + - name: Install Ubuntu dependencies + if: matrix.os == 'ubuntu-20.04' + run: | + sudo apt install build-essential pkg-config cmake ninja-build curl autoconf automake libtool + # Firefox version dependencies + sudo apt install python3-pip python-is-python3 + pip install gyp-next + # Chrome version dependencies + sudo apt install golang-go + # Needed to compile 'minicurl' + sudo apt install libcurl4-openssl-dev + + - name: Check out the repo + uses: actions/checkout@v2 + + - name: Install dependencies for the tests script + run: | + pip install -r tests/requirements.txt + + - name: Run configure script + run: | + autoconf + mkdir ${{ runner.temp }}/install + ./configure --prefix=${{ runner.temp }}/install + + - name: Build the Chrome version of curl-impersonate + run: | + make chrome-build + make chrome-install + + - name: Build the Firefox version of curl-impersonate + run: | + make firefox-build + make firefox-install + + - name: Prepare the tests + run: | + # Compile 'minicurl' which is used by the tests + gcc -Wall -Werror -o ${{ runner.temp }}/install/bin/minicurl tests/minicurl.c `curl-config --libs` + + - name: Run the tests + run: | + cd tests + pytest . --log-cli-level DEBUG --install-dir ${{ runner.temp}}/install From f1324f7718efc0e4f104ba7029a5baa00d4165ba Mon Sep 17 00:00:00 2001 From: lwthiker Date: Tue, 12 Apr 2022 16:55:00 +0300 Subject: [PATCH 11/15] Add Badge for the native-build GitHub Action --- README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index bdcaacd..720d3f9 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,6 @@ -# curl-impersonate · ![workflow](https://github.com/lwthiker/curl-impersonate/actions/workflows/build-and-test-docker.yml/badge.svg) +# curl-impersonate +![workflow](https://github.com/lwthiker/curl-impersonate/actions/workflows/build-and-test-docker.yml/badge.svg) +![workflow](https://github.com/lwthiker/curl-impersonate/actions/workflows/build-and-test-make.yml/badge.svg) A special compilation of [curl](https://github.com/curl/curl) that makes it impersonate real browsers. It can impersonate the four major browsers: Chrome, Edge, Safari & Firefox. This curl binary is able to perform a TLS handshake that is identical to that of a real browser. From 184fa640e8649d46e4420af101d82ecbe1553bde Mon Sep 17 00:00:00 2001 From: lwthiker Date: Tue, 12 Apr 2022 17:11:22 +0300 Subject: [PATCH 12/15] Support Python 3.8 in the tests --- tests/test_impersonate.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_impersonate.py b/tests/test_impersonate.py index ffc4bbb..503f1a5 100644 --- a/tests/test_impersonate.py +++ b/tests/test_impersonate.py @@ -257,7 +257,7 @@ class TestImpersonation: def _run_curl(self, curl_binary, env_vars, extra_args, url): env = os.environ.copy() if env_vars: - env |= env_vars + env.update(env_vars) logging.debug(f"Launching '{curl_binary}' to {url}") if env_vars: From e04e53b4d55120201d6ab7fd54f3be73d82b8c41 Mon Sep 17 00:00:00 2001 From: lwthiker Date: Tue, 12 Apr 2022 17:32:29 +0300 Subject: [PATCH 13/15] Use 'sudo' to launch pytest (because of tcpdump) --- .github/workflows/build-and-test-make.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build-and-test-make.yml b/.github/workflows/build-and-test-make.yml index 93f7ab4..b62d2fc 100644 --- a/.github/workflows/build-and-test-make.yml +++ b/.github/workflows/build-and-test-make.yml @@ -59,4 +59,4 @@ jobs: - name: Run the tests run: | cd tests - pytest . --log-cli-level DEBUG --install-dir ${{ runner.temp}}/install + sudo pytest . --log-cli-level DEBUG --install-dir ${{ runner.temp}}/install From f1b31726dcadec75eaa283357bc1e09a7c7f3b2b Mon Sep 17 00:00:00 2001 From: lwthiker Date: Tue, 12 Apr 2022 21:59:26 +0300 Subject: [PATCH 14/15] Fix action failing on running pytest as sudo --- .github/workflows/build-and-test-make.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/build-and-test-make.yml b/.github/workflows/build-and-test-make.yml index b62d2fc..e4b184d 100644 --- a/.github/workflows/build-and-test-make.yml +++ b/.github/workflows/build-and-test-make.yml @@ -33,7 +33,8 @@ jobs: - name: Install dependencies for the tests script run: | - pip install -r tests/requirements.txt + # Install globally so that we can run 'pytest' with 'sudo' + sudo pip install -r tests/requirements.txt - name: Run configure script run: | @@ -59,4 +60,5 @@ jobs: - name: Run the tests run: | cd tests + # sudo is needed for capturing packets sudo pytest . --log-cli-level DEBUG --install-dir ${{ runner.temp}}/install From 842415f119f9fd9d7687f50a5f04944765e04185 Mon Sep 17 00:00:00 2001 From: lwthiker Date: Tue, 12 Apr 2022 22:19:43 +0300 Subject: [PATCH 15/15] Add missing tests dependency in GitHub action --- .github/workflows/build-and-test-make.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/build-and-test-make.yml b/.github/workflows/build-and-test-make.yml index e4b184d..4433035 100644 --- a/.github/workflows/build-and-test-make.yml +++ b/.github/workflows/build-and-test-make.yml @@ -27,6 +27,8 @@ jobs: sudo apt install golang-go # Needed to compile 'minicurl' sudo apt install libcurl4-openssl-dev + # More dependencies for the tests + sudo apt install tcpdump nghttp2-server libnss3 - name: Check out the repo uses: actions/checkout@v2