Compare commits

...

11 Commits

Author SHA1 Message Date
MCG-pok
f75994197c Update css selector to get shadowed iframe 2024-08-14 14:05:04 +03:00
MCG-pok
42714b248f add js click on iframe_body 2024-08-14 14:05:04 +03:00
MCG-pok
2900c58165 Access iframe in closed shadow root + click on checkbox from iframe body 2024-08-14 14:05:04 +03:00
ilike2burnthing
a798561338 Bump requests version
*.0 was yanked
2024-07-30 02:38:13 +01:00
Bogdan
eb680efc90 Don't build docker images for PRs from forks (#1281) 2024-07-20 22:08:40 +03:00
ilike2burnthing
0f8f0bec25 revert and bump action version 2024-07-20 19:41:49 +01:00
ilike2burnthing
3d9bc5627b Change to GITHUB_TOKEN for GHRC login 2024-07-20 14:21:34 +01:00
ilike2burnthing
dd7eaee2e3 Bump requirements
resolves Dependabot alerts
2024-07-12 17:11:40 +01:00
ilike2burnthing
031177bbdb Bump version 3.3.21 (#1240) 2024-06-26 02:14:25 +01:00
Bogdan
a8644532a1 Escape values for generated form used in request.post (#1236)
and build docker images for PRs
2024-06-26 02:04:59 +01:00
ilike2burnthing
e96161c873 Add challenge selector to catch reloading page on non-English systems. resolves #1237 2024-06-25 22:32:06 +01:00
6 changed files with 93 additions and 49 deletions

View File

@@ -4,50 +4,64 @@ on:
push:
tags:
- 'v*.*.*'
pull_request:
branches:
- master
concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true
jobs:
build-docker-images:
if: ${{ !github.event.pull_request.head.repo.fork }}
runs-on: ubuntu-22.04
steps:
-
name: Checkout
uses: actions/checkout@v3
-
name: Downcase repo
- name: Checkout
uses: actions/checkout@v4
- name: Downcase repo
run: echo REPOSITORY=$(echo ${{ github.repository }} | tr '[:upper:]' '[:lower:]') >> $GITHUB_ENV
-
name: Docker meta
- name: Docker meta
id: docker_meta
uses: crazy-max/ghaction-docker-meta@v3
uses: docker/metadata-action@v5
with:
images: ${{ env.REPOSITORY }},ghcr.io/${{ env.REPOSITORY }}
tag-sha: false
-
name: Set up QEMU
uses: docker/setup-qemu-action@v2
-
name: Set up Docker Buildx
uses: docker/setup-buildx-action@v2
-
name: Login to DockerHub
uses: docker/login-action@v2
images: |
${{ env.REPOSITORY }},enable=${{ github.event_name != 'pull_request' }}
ghcr.io/${{ env.REPOSITORY }}
tags: |
type=semver,pattern={{version}},prefix=v
type=ref,event=pr
flavor: |
latest=auto
- name: Set up QEMU
uses: docker/setup-qemu-action@v3
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Login to DockerHub
uses: docker/login-action@v3
if: github.event_name != 'pull_request'
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
-
name: Login to GitHub Container Registry
uses: docker/login-action@v2
- name: Login to GitHub Container Registry
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.repository_owner }}
password: ${{ secrets.GH_PAT }}
-
name: Build and push
uses: docker/build-push-action@v3
- name: Build and push
uses: docker/build-push-action@v6
with:
context: .
file: ./Dockerfile
platforms: linux/386,linux/amd64,linux/arm/v7,linux/arm64/v8
push: ${{ github.event_name != 'pull_request' }}
push: true
tags: ${{ steps.docker_meta.outputs.tags }}
labels: ${{ steps.docker_meta.outputs.labels }}

View File

@@ -1,5 +1,9 @@
# Changelog
## v3.3.21 (2024/06/26)
* Add challenge selector to catch reloading page on non-English systems
* Escape values for generated form used in request.post. Thanks @mynameisbogdan
## v3.3.20 (2024/06/21)
* maxTimeout should always be int
* Check not running in Docker before logging version_main error

View File

@@ -62,17 +62,17 @@ ENTRYPOINT ["/usr/bin/dumb-init", "--"]
CMD ["/usr/local/bin/python", "-u", "/app/flaresolverr.py"]
# Local build
# docker build -t ngosang/flaresolverr:3.3.20 .
# docker run -p 8191:8191 ngosang/flaresolverr:3.3.20
# docker build -t ngosang/flaresolverr:3.3.21 .
# docker run -p 8191:8191 ngosang/flaresolverr:3.3.21
# Multi-arch build
# docker run --rm --privileged multiarch/qemu-user-static --reset -p yes
# docker buildx create --use
# docker buildx build -t ngosang/flaresolverr:3.3.20 --platform linux/386,linux/amd64,linux/arm/v7,linux/arm64/v8 .
# docker buildx build -t ngosang/flaresolverr:3.3.21 --platform linux/386,linux/amd64,linux/arm/v7,linux/arm64/v8 .
# add --push to publish in DockerHub
# Test multi-arch build
# docker run --rm --privileged multiarch/qemu-user-static --reset -p yes
# docker buildx create --use
# docker buildx build -t ngosang/flaresolverr:3.3.20 --platform linux/arm/v7 --load .
# docker run -p 8191:8191 --platform linux/arm/v7 ngosang/flaresolverr:3.3.20
# docker buildx build -t ngosang/flaresolverr:3.3.21 --platform linux/arm/v7 --load .
# docker run -p 8191:8191 --platform linux/arm/v7 ngosang/flaresolverr:3.3.21

View File

@@ -1,6 +1,6 @@
{
"name": "flaresolverr",
"version": "3.3.20",
"version": "3.3.21",
"description": "Proxy server to bypass Cloudflare protection",
"author": "Diego Heras (ngosang / ngosang@hotmail.es)",
"license": "MIT"

View File

@@ -4,8 +4,8 @@ selenium==4.15.2
func-timeout==4.3.5
prometheus-client==0.17.1
# required by undetected_chromedriver
requests==2.31.0
certifi==2023.7.22
requests==2.32.3
certifi==2024.07.04
websockets==11.0.3
# only required for linux and macos
xvfbwrapper==0.2.9; platform_system != "Windows"

View File

@@ -3,7 +3,8 @@ import platform
import sys
import time
from datetime import timedelta
from urllib.parse import unquote
from html import escape
from urllib.parse import unquote, quote
from func_timeout import FunctionTimedOut, func_timeout
from selenium.common import TimeoutException
@@ -40,7 +41,7 @@ CHALLENGE_TITLES = [
]
CHALLENGE_SELECTORS = [
# Cloudflare
'#cf-challenge-running', '.ray_id', '.attack-box', '#cf-please-wait', '#challenge-spinner', '#trk_jschal_js', '#turnstile-wrapper',
'#cf-challenge-running', '.ray_id', '.attack-box', '#cf-please-wait', '#challenge-spinner', '#trk_jschal_js', '#turnstile-wrapper', '.lds-ring',
# Custom CloudFlare for EbookParadijs, Film-Paleis, MuziekFabriek and Puur-Hollands
'td.info #js_info',
# Fairlane / pararius.com
@@ -218,6 +219,20 @@ def _cmd_sessions_destroy(req: V1RequestBase) -> V1ResponseBase:
"message": "The session has been removed."
})
def _init_driver(driver):
try:
driver.execute_cdp_cmd('Page.enable', {})
driver.execute_cdp_cmd('Page.addScriptToEvaluateOnNewDocument', {
'source': """
Element.prototype._as = Element.prototype.attachShadow;
Element.prototype.attachShadow = function (params) {
return this._as({mode: "open"})
};
"""
})
except Exception as e:
logging.debug("Driver init exception: %s", repr(e))
def _resolve_challenge(req: V1RequestBase, method: str) -> ChallengeResolutionT:
timeout = int(req.maxTimeout) / 1000
@@ -238,6 +253,7 @@ def _resolve_challenge(req: V1RequestBase, method: str) -> ChallengeResolutionT:
else:
driver = utils.get_webdriver(req.proxy)
logging.debug('New instance of webdriver has been created to perform the request')
_init_driver(driver)
return func_timeout(timeout, _evil_logic, (req, driver, method))
except FunctionTimedOut:
raise Exception(f'Error solving the challenge. Timeout after {timeout} seconds.')
@@ -251,23 +267,33 @@ def _resolve_challenge(req: V1RequestBase, method: str) -> ChallengeResolutionT:
logging.debug('A used instance of webdriver has been destroyed')
def get_shadowed_iframe(driver: WebDriver, css_selector: str):
logging.debug("Getting ShadowRoot by selector: %s", css_selector)
shadow_element = driver.execute_script("""
return document.querySelector(arguments[0]).shadowRoot.firstChild;
""", css_selector)
if shadow_element:
logging.debug("iframe found")
else:
logging.debug("iframe not found")
return shadow_element
def click_verify(driver: WebDriver):
try:
logging.debug("Try to find the Cloudflare verify checkbox...")
iframe = driver.find_element(By.XPATH, "//iframe[starts-with(@id, 'cf-chl-widget-')]")
iframe = get_shadowed_iframe(driver, "div:not(:has(div))")
driver.switch_to.frame(iframe)
checkbox = driver.find_element(
by=By.XPATH,
value='//*[@id="content"]/div/div/label/input',
)
if checkbox:
iframe_body = driver.find_element(By.CSS_SELECTOR, "body")
if iframe_body:
iframe_body.click()
actions = ActionChains(driver)
actions.move_to_element_with_offset(checkbox, 5, 7)
actions.click(checkbox)
actions.move_to_element_with_offset(iframe_body, 10, 10)
actions.click(iframe_body)
actions.perform()
logging.debug("Cloudflare verify checkbox found and clicked!")
except Exception:
logging.debug("Cloudflare verify checkbox not found on the page.")
logging.debug("Attempted to click on iframe body")
except Exception as e:
logging.debug("Cloudflare verify checkbox not found on the page. %s", repr(e))
finally:
driver.switch_to.default_content()
@@ -439,7 +465,7 @@ def _post_request(req: V1RequestBase, driver: WebDriver):
value = unquote(parts[1])
except Exception:
value = parts[1]
post_form += f'<input type="text" name="{name}" value="{value}"><br>'
post_form += f'<input type="text" name="{escape(quote(name))}" value="{escape(quote(value))}"><br>'
post_form += '</form>'
html_content = f"""
<!DOCTYPE html>
@@ -449,6 +475,6 @@ def _post_request(req: V1RequestBase, driver: WebDriver):
<script>document.getElementById('hackForm').submit();</script>
</body>
</html>"""
driver.get("data:text/html;charset=utf-8," + html_content)
driver.get("data:text/html;charset=utf-8,{html_content}".format(html_content=html_content))
driver.start_session()
driver.start_session() # required to bypass Cloudflare