扫码登录,获取cookies
This commit is contained in:
@@ -3,6 +3,8 @@ Core sign-in business logic service
|
||||
Handles Weibo super topic sign-in operations
|
||||
"""
|
||||
|
||||
import os
|
||||
import sys
|
||||
import asyncio
|
||||
import httpx
|
||||
import logging
|
||||
@@ -10,10 +12,21 @@ import random
|
||||
from datetime import datetime, timedelta
|
||||
from typing import Dict, Any, List, Optional
|
||||
from uuid import UUID
|
||||
from sqlalchemy import select, update
|
||||
|
||||
# Add parent directory to path for imports
|
||||
sys.path.insert(0, os.path.join(os.path.dirname(__file__), "../../.."))
|
||||
|
||||
from shared.models.base import AsyncSessionLocal
|
||||
from shared.models.account import Account
|
||||
from shared.models.signin_log import SigninLog
|
||||
from shared.crypto import decrypt_cookie, derive_key
|
||||
from shared.config import shared_settings
|
||||
|
||||
from app.config import settings
|
||||
from app.models.signin_models import SignInRequest, SignInResult, TaskStatus, WeiboAccount, WeiboSuperTopic, AntiBotConfig
|
||||
from app.services.weibo_client import WeiboClient
|
||||
from app.services.antibot import antibot
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@@ -72,6 +85,15 @@ class SignInService:
|
||||
|
||||
# Step 2: Setup session with proxy and fingerprint
|
||||
task_status.current_step = "setup_session"
|
||||
|
||||
# Verify cookies before proceeding
|
||||
cookies_valid = await self.weibo_client.verify_cookies(account)
|
||||
if not cookies_valid:
|
||||
logger.error(f"Cookies invalid for account {account_id}")
|
||||
# Update account status to invalid_cookie
|
||||
await self._update_account_status(account_id, "invalid_cookie")
|
||||
raise Exception("Cookie validation failed - cookies are invalid or expired")
|
||||
|
||||
await self._apply_anti_bot_protection()
|
||||
|
||||
task_status.steps_completed.append("setup_session")
|
||||
@@ -156,20 +178,31 @@ class SignInService:
|
||||
self.active_tasks[task_id].updated_at = datetime.now()
|
||||
|
||||
async def _get_account_info(self, account_id: str) -> Optional[WeiboAccount]:
|
||||
"""Get Weibo account information from database"""
|
||||
"""
|
||||
Get Weibo account information from database (replaces mock data).
|
||||
Returns account dict or None if not found.
|
||||
"""
|
||||
try:
|
||||
# Mock implementation - in real system, query database
|
||||
# For demo, return mock account
|
||||
return WeiboAccount(
|
||||
id=UUID(account_id),
|
||||
user_id=UUID("12345678-1234-5678-9012-123456789012"),
|
||||
weibo_user_id="1234567890",
|
||||
remark="Demo Account",
|
||||
encrypted_cookies="mock_encrypted_cookies",
|
||||
iv="mock_iv_16_bytes",
|
||||
status="active",
|
||||
last_checked_at=datetime.now() - timedelta(hours=1)
|
||||
)
|
||||
async with AsyncSessionLocal() as session:
|
||||
stmt = select(Account).where(Account.id == account_id)
|
||||
result = await session.execute(stmt)
|
||||
account = result.scalar_one_or_none()
|
||||
|
||||
if not account:
|
||||
logger.error(f"Account {account_id} not found in database")
|
||||
return None
|
||||
|
||||
# Convert ORM model to Pydantic model
|
||||
return WeiboAccount(
|
||||
id=UUID(account.id),
|
||||
user_id=UUID(account.user_id),
|
||||
weibo_user_id=account.weibo_user_id,
|
||||
remark=account.remark or "",
|
||||
encrypted_cookies=account.encrypted_cookies,
|
||||
iv=account.iv,
|
||||
status=account.status,
|
||||
last_checked_at=account.last_checked_at or datetime.now()
|
||||
)
|
||||
except Exception as e:
|
||||
logger.error(f"Error fetching account {account_id}: {e}")
|
||||
return None
|
||||
@@ -177,18 +210,24 @@ class SignInService:
|
||||
async def _apply_anti_bot_protection(self):
|
||||
"""Apply anti-bot protection measures"""
|
||||
# Random delay to mimic human behavior
|
||||
delay = random.uniform(
|
||||
self.antibot_config.random_delay_min,
|
||||
self.antibot_config.random_delay_max
|
||||
)
|
||||
delay = antibot.get_random_delay()
|
||||
logger.debug(f"Applying random delay: {delay:.2f}s")
|
||||
await asyncio.sleep(delay)
|
||||
|
||||
# Additional anti-bot measures would go here:
|
||||
# - User agent rotation
|
||||
# - Proxy selection
|
||||
# - Browser fingerprint simulation
|
||||
# - Request header randomization
|
||||
# Get random User-Agent
|
||||
user_agent = antibot.get_random_user_agent()
|
||||
logger.debug(f"Using User-Agent: {user_agent[:50]}...")
|
||||
|
||||
# Try to get proxy (falls back to direct connection if unavailable)
|
||||
proxy = await antibot.get_proxy()
|
||||
if proxy:
|
||||
logger.info(f"Using proxy for requests")
|
||||
else:
|
||||
logger.info("Using direct connection (no proxy available)")
|
||||
|
||||
# Get browser fingerprint
|
||||
fingerprint = antibot.get_fingerprint_data()
|
||||
logger.debug(f"Browser fingerprint: {fingerprint}")
|
||||
|
||||
async def _get_super_topics_list(self, account: WeiboAccount) -> List[WeiboSuperTopic]:
|
||||
"""Get list of super topics for account"""
|
||||
@@ -244,10 +283,18 @@ class SignInService:
|
||||
|
||||
if topic.is_signed:
|
||||
already_signed.append(topic.title)
|
||||
# Write log for already signed
|
||||
await self._write_signin_log(
|
||||
account_id=str(account.id),
|
||||
topic_title=topic.title,
|
||||
status="failed_already_signed",
|
||||
reward_info=None,
|
||||
error_message="Already signed today"
|
||||
)
|
||||
continue
|
||||
|
||||
# Execute signin for this topic
|
||||
success = await self.weibo_client.sign_super_topic(
|
||||
success, reward_info, error_msg = await self.weibo_client.sign_super_topic(
|
||||
account=account,
|
||||
topic=topic,
|
||||
task_id=task_id
|
||||
@@ -256,16 +303,88 @@ class SignInService:
|
||||
if success:
|
||||
signed.append(topic.title)
|
||||
logger.info(f"✅ Successfully signed topic: {topic.title}")
|
||||
|
||||
# Write success log
|
||||
await self._write_signin_log(
|
||||
account_id=str(account.id),
|
||||
topic_title=topic.title,
|
||||
status="success",
|
||||
reward_info=reward_info,
|
||||
error_message=None
|
||||
)
|
||||
else:
|
||||
errors.append(f"Failed to sign topic: {topic.title}")
|
||||
|
||||
# Write failure log
|
||||
await self._write_signin_log(
|
||||
account_id=str(account.id),
|
||||
topic_title=topic.title,
|
||||
status="failed_network",
|
||||
reward_info=None,
|
||||
error_message=error_msg
|
||||
)
|
||||
|
||||
except Exception as e:
|
||||
error_msg = f"Error signing topic {topic.title}: {str(e)}"
|
||||
logger.error(error_msg)
|
||||
errors.append(error_msg)
|
||||
|
||||
# Write error log
|
||||
await self._write_signin_log(
|
||||
account_id=str(account.id),
|
||||
topic_title=topic.title,
|
||||
status="failed_network",
|
||||
reward_info=None,
|
||||
error_message=str(e)
|
||||
)
|
||||
|
||||
return {
|
||||
"signed": signed,
|
||||
"already_signed": already_signed,
|
||||
"errors": errors
|
||||
}
|
||||
|
||||
async def _write_signin_log(
|
||||
self,
|
||||
account_id: str,
|
||||
topic_title: str,
|
||||
status: str,
|
||||
reward_info: Optional[Dict[str, Any]],
|
||||
error_message: Optional[str]
|
||||
):
|
||||
"""
|
||||
Write signin result to signin_logs table.
|
||||
Replaces mock implementation with real database write.
|
||||
"""
|
||||
try:
|
||||
async with AsyncSessionLocal() as session:
|
||||
log = SigninLog(
|
||||
account_id=account_id,
|
||||
topic_title=topic_title,
|
||||
status=status,
|
||||
reward_info=reward_info,
|
||||
error_message=error_message,
|
||||
)
|
||||
session.add(log)
|
||||
await session.commit()
|
||||
logger.debug(f"Wrote signin log for account {account_id}, topic {topic_title}, status {status}")
|
||||
except Exception as e:
|
||||
logger.error(f"Failed to write signin log: {e}")
|
||||
|
||||
async def _update_account_status(self, account_id: str, status: str):
|
||||
"""
|
||||
Update account status in database.
|
||||
Used when cookie is invalid or account is banned.
|
||||
"""
|
||||
try:
|
||||
async with AsyncSessionLocal() as session:
|
||||
stmt = (
|
||||
update(Account)
|
||||
.where(Account.id == account_id)
|
||||
.values(status=status, last_checked_at=datetime.now())
|
||||
)
|
||||
await session.execute(stmt)
|
||||
await session.commit()
|
||||
logger.info(f"Updated account {account_id} status to {status}")
|
||||
except Exception as e:
|
||||
logger.error(f"Failed to update account status: {e}")
|
||||
|
||||
Reference in New Issue
Block a user