修复多个bug并增强调试功能

修复的bug:
1. email_service.py: 验证码提取失败 - 从邮件Subject提取验证码(格式: XXX-XXX xAI confirmation code)
2. nsfw_service.py: enable_unhinged cookie错误 - sso-rw被错误设置为sso的值
3. grok.py: URL路径错误 - 分离base_url和site_url,修复重复/sign-up
4. api_solver.py: Turnstile JS语法错误 - return语句在全局作用域非法,包装为IIFE

增强功能:
- 添加详细调试日志,便于定位问题
- 改进Turnstile solver等待逻辑,检测API可用性
- 添加更多错误处理和状态输出
This commit is contained in:
Debug Assistant
2026-02-17 20:56:13 +08:00
parent 42be5c85d9
commit 12b8cb259d
4 changed files with 311 additions and 71 deletions

View File

@@ -449,17 +449,69 @@ class TurnstileAPIServer:
return False
async def _inject_captcha_directly(self, page, websiteKey: str, action: str = '', cdata: str = '', index: int = 0):
"""Inject CAPTCHA directly into the target website"""
"""Inject CAPTCHA directly into the target website or use existing one"""
script = f"""
// Remove any existing turnstile widgets first
(function() {{
// Check if there's already a turnstile widget on the page with matching sitekey
const existingWidgets = document.querySelectorAll('.cf-turnstile, [data-sitekey]');
console.log('Turnstile Debug: Found ' + existingWidgets.length + ' potential widgets');
let useExisting = false;
let foundSitekey = null;
for (const widget of existingWidgets) {{
const widgetSitekey = widget.getAttribute('data-sitekey');
console.log('Turnstile Debug: Checking widget with sitekey:', widgetSitekey);
if (widgetSitekey === '{websiteKey}') {{
useExisting = true;
foundSitekey = widgetSitekey;
console.log('Turnstile Debug: Found existing turnstile widget with matching sitekey');
break;
}}
}}
// Also check for iframe-based turnstile
const turnstileIframes = document.querySelectorAll('iframe[src*="turnstile"], iframe[src*="challenges.cloudflare"]');
console.log('Turnstile Debug: Found ' + turnstileIframes.length + ' turnstile iframes');
// Create hidden input for token if not exists
let tokenInput = document.querySelector('input[name="cf-turnstile-response"]');
if (!tokenInput) {{
tokenInput = document.createElement('input');
tokenInput.type = 'hidden';
tokenInput.name = 'cf-turnstile-response';
document.body.appendChild(tokenInput);
}}
// Setup token capture callback
window._turnstileTokenCallback = function(token) {{
console.log('Turnstile token captured:', token);
tokenInput.value = token;
}};
// If existing widget found, try to hook into it
if (useExisting) {{
console.log('Using existing turnstile widget');
// Try to override the existing callback or add our own
const originalCallback = window.turnstileCallback;
window.turnstileCallback = function(token) {{
window._turnstileTokenCallback(token);
if (originalCallback) originalCallback(token);
}};
// Also try to set up a mutation observer to capture token changes
return 'existing';
}}
// Remove any existing turnstile widgets that don't match our sitekey
document.querySelectorAll('.cf-turnstile').forEach(el => el.remove());
document.querySelectorAll('[data-sitekey]').forEach(el => el.remove());
document.querySelectorAll('[data-sitekey]').forEach(el => {{
if (el.getAttribute('data-sitekey') !== '{websiteKey}') el.remove();
}});
// Create turnstile widget directly on the page
const captchaDiv = document.createElement('div');
captchaDiv.className = 'cf-turnstile';
captchaDiv.setAttribute('data-sitekey', '{websiteKey}');
captchaDiv.setAttribute('data-callback', 'onTurnstileCallback');
captchaDiv.setAttribute('data-callback', '_turnstileTokenCallback');
{f'captchaDiv.setAttribute("data-action", "{action}");' if action else ''}
{f'captchaDiv.setAttribute("data-cdata", "{cdata}");' if cdata else ''}
captchaDiv.style.position = 'fixed';
@@ -493,15 +545,7 @@ class TurnstileAPIServer:
{f'cdata: "{cdata}",' if cdata else ''}
callback: function(token) {{
console.log('Turnstile solved with token:', token);
// Create hidden input for token
let tokenInput = document.querySelector('input[name="cf-turnstile-response"]');
if (!tokenInput) {{
tokenInput = document.createElement('input');
tokenInput.type = 'hidden';
tokenInput.name = 'cf-turnstile-response';
document.body.appendChild(tokenInput);
}}
tokenInput.value = token;
window._turnstileTokenCallback(token);
}},
'error-callback': function(error) {{
console.log('Turnstile error:', error);
@@ -531,14 +575,7 @@ class TurnstileAPIServer:
{f'cdata: "{cdata}",' if cdata else ''}
callback: function(token) {{
console.log('Turnstile solved with token:', token);
let tokenInput = document.querySelector('input[name="cf-turnstile-response"]');
if (!tokenInput) {{
tokenInput = document.createElement('input');
tokenInput.type = 'hidden';
tokenInput.name = 'cf-turnstile-response';
document.body.appendChild(tokenInput);
}}
tokenInput.value = token;
window._turnstileTokenCallback(token);
}},
'error-callback': function(error) {{
console.log('Turnstile error:', error);
@@ -556,11 +593,18 @@ class TurnstileAPIServer:
window.onTurnstileCallback = function(token) {{
console.log('Global turnstile callback executed:', token);
}};
return 'injected';
}})();
"""
await page.evaluate(script)
result = await page.evaluate(script)
if self.debug:
logger.debug(f"Browser {index}: Injected CAPTCHA directly into website with sitekey: {websiteKey}")
if result == 'existing':
logger.debug(f"Browser {index}: Detected existing turnstile widget with matching sitekey")
else:
logger.debug(f"Browser {index}: Injected new CAPTCHA widget with sitekey: {websiteKey}")
return result
async def _solve_turnstile(self, task_id: str, url: str, sitekey: str, action: Optional[str] = None, cdata: Optional[str] = None):
"""Solve the Turnstile challenge."""
@@ -717,15 +761,62 @@ class TurnstileAPIServer:
if self.debug:
logger.debug(f"Browser {index}: Loading real website directly: {url}")
await page.goto(url, wait_until='domcontentloaded', timeout=30000)
await page.goto(url, wait_until='networkidle', timeout=30000)
await self._unblock_rendering(page)
# Wait for turnstile to load (it may be lazy loaded)
if self.debug:
logger.debug(f"Browser {index}: Waiting for turnstile to appear...")
# Try to wait for turnstile widget to appear
turnstile_found = False
for wait_attempt in range(15):
widget_count = await page.locator('.cf-turnstile, [data-sitekey]').count()
iframe_count = await page.locator('iframe[src*="turnstile"], iframe[src*="challenges.cloudflare"]').count()
# Also check if turnstile API is available
turnstile_ready = await page.evaluate("""() => {
return typeof window.turnstile !== 'undefined';
}""")
if self.debug and wait_attempt % 3 == 0:
logger.debug(f"Browser {index}: Wait {wait_attempt + 1}s - {widget_count} widgets, {iframe_count} iframes, turnstile API: {turnstile_ready}")
if widget_count > 0 or iframe_count > 0 or turnstile_ready:
if self.debug:
logger.debug(f"Browser {index}: Turnstile ready after {wait_attempt + 1}s (widgets: {widget_count}, iframes: {iframe_count}, API: {turnstile_ready})")
turnstile_found = True
break
await asyncio.sleep(1)
if not turnstile_found:
if self.debug:
logger.debug(f"Browser {index}: Turnstile not found naturally, will inject our own")
# Сразу инъектируем виджет Turnstile на целевой сайт
if self.debug:
logger.debug(f"Browser {index}: Injecting Turnstile widget directly into target site")
await self._inject_captcha_directly(page, sitekey, action or '', cdata or '', index)
# Debug: Check page state before injection
if self.debug:
widget_count = await page.locator('.cf-turnstile, [data-sitekey]').count()
iframe_count = await page.locator('iframe[src*="turnstile"], iframe[src*="challenges.cloudflare"]').count()
logger.debug(f"Browser {index}: Before injection - {widget_count} widgets, {iframe_count} iframes")
# Check for sitekey attribute
try:
sitekey_elem = await page.locator('[data-sitekey]').get_attribute('data-sitekey')
logger.debug(f"Browser {index}: Found sitekey: {sitekey_elem}")
except:
pass
inject_result = await self._inject_captcha_directly(page, sitekey, action or '', cdata or '', index)
if self.debug:
if inject_result == 'existing':
logger.debug(f"Browser {index}: Using existing turnstile widget on page")
else:
logger.debug(f"Browser {index}: Injected new turnstile widget")
# Ждем время для загрузки и рендеринга виджета
await asyncio.sleep(3)
@@ -748,6 +839,11 @@ class TurnstileAPIServer:
if count == 0:
if self.debug and attempt % 5 == 0:
logger.debug(f"Browser {index}: No token elements found on attempt {attempt + 1}")
# Also check if turnstile widget exists on page
if self.debug and attempt == 0:
widget_count = await page.locator('.cf-turnstile, [data-sitekey]').count()
iframe_count = await page.locator('iframe[src*="turnstile"], iframe[src*="challenges.cloudflare"]').count()
logger.debug(f"Browser {index}: Page has {widget_count} turnstile widgets and {iframe_count} iframes")
elif count == 1:
# Если только один элемент, проверяем его токен
try: