diff --git a/user_scanner/user_scan/adult/bdsmsingles.py b/user_scanner/user_scan/adult/bdsmsingles.py index c8f88b8d..f2fbe71b 100644 --- a/user_scanner/user_scan/adult/bdsmsingles.py +++ b/user_scanner/user_scan/adult/bdsmsingles.py @@ -1,12 +1,37 @@ +import hashlib import re -from user_scanner.core.orchestrator import generic_validate, Result +from user_scanner.core.orchestrator import Result, generic_validate, make_request -def validate_bdsmsingles(user): + +def validate_bdsmsingles(user: str) -> Result: url = f"https://www.bdsmsingles.com/members/{user}/" show_url = url def process(response): + if response.status_code == 202: + challenge = re.search( + r'prefix="([0-9a-f]+)",win="(\d+)",diff=(\d+)', response.text + ) + if not challenge or challenge.group(3) != "4": + return Result.error("Unsupported browser challenge.", url=show_url) + + prefix, window, _ = challenge.groups() + nonce = next( + ( + value + for value in range(1 << 20) + if hashlib.sha256(f"{prefix}{value}".encode()) + .hexdigest() + .startswith("0000") + ), + None, + ) + if nonce is None: + return Result.error("Could not solve browser challenge.", url=show_url) + + response = make_request(url, cookies={"_jscp": f"{window}.{nonce}"}) + if response.status_code == 200 and "
\s*(.*?)\s*
", response.text, re.DOTALL) + r"\s*\s*(.*?)\s*
", response.text, re.DOTALL + ) if info_match: # Clean up multiple whitespaces cleaned_info = re.sub(r"\s+", " ", info_match.group(1)).strip() @@ -28,7 +54,9 @@ def process(response): # Avatar (if not default nophoto svg) avatar_match = re.search( - r'src="(https://media\.bdsmsingles\.com/images/user_photo/[^"]+)"', response.text) + r'src="(https://media\.bdsmsingles\.com/images/user_photo/[^"]+)"', + response.text, + ) if avatar_match and "nophoto" not in avatar_match.group(1): media["image"] = avatar_match.group(1) @@ -36,8 +64,7 @@ def process(response): def extract_table_field(field_name): # Search for field label followed by its value div pattern = rf"{field_name}\s*