Merge 668e0aeca1e3dbe20dc13d3431b9d9181fb84a90 into 3e51ac11889bc4e1b577e4cedce62ed7c8c056b8

This commit is contained in:
Wyatt Henke 2025-06-26 23:15:35 +01:00 committed by GitHub
commit d3ba9a5907
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 69 additions and 31 deletions

View File

@ -11,3 +11,5 @@ websockets==11.0.3
xvfbwrapper==0.2.9; platform_system != "Windows"
# only required for windows
pefile==2023.2.7; platform_system == "Windows"
selenium_fetch

View File

@ -19,6 +19,7 @@ class ChallengeResolutionT:
status: str = None
message: str = None
result: ChallengeResolutionResultT = None
response: str = None
def __init__(self, _dict):
self.__dict__.update(_dict)
@ -39,6 +40,7 @@ class V1RequestBase(object):
# V1Request
url: str = None
contentType: str = None
postData: str = None
returnOnlyCookies: bool = None
download: bool = None # deprecated v2.0.0, not used

View File

@ -1,3 +1,4 @@
import json
import logging
import platform
import sys
@ -9,12 +10,13 @@ from urllib.parse import unquote, quote
from func_timeout import FunctionTimedOut, func_timeout
from selenium.common import TimeoutException
from selenium.webdriver.chrome.webdriver import WebDriver
from selenium.webdriver.common.action_chains import ActionChains
from selenium.webdriver.common.by import By
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.support.expected_conditions import (
presence_of_element_located, staleness_of, title_is)
from selenium.webdriver.common.action_chains import ActionChains
from selenium.webdriver.support.wait import WebDriverWait
from selenium_fetch import fetch, Options
import utils
from dtos import (STATUS_ERROR, STATUS_OK, ChallengeResolutionResultT,
@ -148,6 +150,8 @@ def _cmd_request_get(req: V1RequestBase) -> V1ResponseBase:
raise Exception("Request parameter 'url' is mandatory in 'request.get' command.")
if req.postData is not None:
raise Exception("Cannot use 'postBody' when sending a GET request.")
if req.contentType is not None:
raise Exception("Cannot use 'contentType' when sending a GET request.")
if req.returnRawHtml is not None:
logging.warning("Request parameter 'returnRawHtml' was removed in FlareSolverr v2.")
if req.download is not None:
@ -165,6 +169,8 @@ def _cmd_request_post(req: V1RequestBase) -> V1ResponseBase:
# do some validations
if req.postData is None:
raise Exception("Request parameter 'postData' is mandatory in 'request.post' command.")
if req.contentType is None:
raise Exception("Request parameter 'contentType' is mandatory in 'request.post' command.")
if req.returnRawHtml is not None:
logging.warning("Request parameter 'returnRawHtml' was removed in FlareSolverr v2.")
if req.download is not None:
@ -178,6 +184,23 @@ def _cmd_request_post(req: V1RequestBase) -> V1ResponseBase:
return res
def _cmd_request_postJSON(req: V1RequestBase) -> V1ResponseBase:
# do some validations
if req.postData is None:
raise Exception("Request parameter 'postData' is mandatory in 'request.post' command.")
if req.returnRawHtml is not None:
logging.warning("Request parameter 'returnRawHtml' was removed in FlareSolverr v2.")
if req.download is not None:
logging.warning("Request parameter 'download' was removed in FlareSolverr v2.")
challenge_res = _resolve_challenge(req, 'POSTJSON')
res = V1ResponseBase({})
res.status = challenge_res.status
res.message = challenge_res.message
res.solution = challenge_res.result
return res
def _cmd_sessions_create(req: V1RequestBase) -> V1ResponseBase:
logging.debug("Creating new session...")
@ -291,7 +314,7 @@ def _evil_logic(req: V1RequestBase, driver: WebDriver, method: str) -> Challenge
# navigate to the page
logging.debug(f'Navigating to... {req.url}')
if method == 'POST':
_post_request(req, driver)
res.response = _post_request(req, driver)
else:
driver.get(req.url)
@ -303,7 +326,7 @@ def _evil_logic(req: V1RequestBase, driver: WebDriver, method: str) -> Challenge
driver.add_cookie(cookie)
# reload the page
if method == 'POST':
_post_request(req, driver)
res.response = _post_request(req, driver)
else:
driver.get(req.url)
@ -397,31 +420,42 @@ def _evil_logic(req: V1RequestBase, driver: WebDriver, method: str) -> Challenge
def _post_request(req: V1RequestBase, driver: WebDriver):
post_form = f'<form id="hackForm" action="{req.url}" method="POST">'
query_string = req.postData if req.postData[0] != '?' else req.postData[1:]
pairs = query_string.split('&')
for pair in pairs:
parts = pair.split('=')
# noinspection PyBroadException
try:
name = unquote(parts[0])
except Exception:
name = parts[0]
if name == 'submit':
continue
# noinspection PyBroadException
try:
value = unquote(parts[1])
except Exception:
value = parts[1]
post_form += f'<input type="text" name="{escape(quote(name))}" value="{escape(quote(value))}"><br>'
post_form += '</form>'
html_content = f"""
<!DOCTYPE html>
<html>
<body>
{post_form}
<script>document.getElementById('hackForm').submit();</script>
</body>
</html>"""
driver.get("data:text/html;charset=utf-8,{html_content}".format(html_content=html_content))
if req.contentType == 'application/x-www-form-urlencoded':
post_form = f'<form id="hackForm" action="{req.url}" method="POST">'
query_string = req.postData if req.postData[0] != '?' else req.postData[1:]
pairs = query_string.split('&')
for pair in pairs:
parts = pair.split('=')
# noinspection PyBroadException
try:
name = unquote(parts[0])
except Exception:
name = parts[0]
if name == 'submit':
continue
# noinspection PyBroadException
try:
value = unquote(parts[1])
except Exception:
value = parts[1]
post_form += f'<input type="text" name="{escape(quote(name))}" value="{escape(quote(value))}"><br>'
post_form += '</form>'
html_content = f"""
<!DOCTYPE html>
<html>
<body>
{post_form}
<script>document.getElementById('hackForm').submit();</script>
</body>
</html>"""
driver.get("data:text/html;charset=utf-8,{html_content}".format(html_content=html_content))
return "Success"
elif req.contentType == 'application/json':
post_data = json.loads(unquote(req.postData))
options = Options(method="POST", body=post_data)
logging.debug(f"Request => POST /v1 options: {utils.object_to_dict(options)}")
response = fetch(driver, req.url, options)
logging.debug(f"Response => POST /v1 response: {utils.object_to_dict(response)}")
return response.text
else:
raise Exception(f"Request parameter 'contentType' = '{req.contentType}' is invalid.")