import requests import json import time import random import string import hashlib from typing import Optional, Dict, Any from dotenv import load_dotenv import os from captcha_solver import TwoCaptchaSolver from tracker import DataTracker from email_manager import EmailManager, AutoEmailVerification from colorama import init, Fore, Style # 初始化 colorama init(autoreset=True) class DuoPlusRegister: """DuoPlus 协议注册类""" def __init__(self, captcha_api_key: str): self.session = requests.Session() self.captcha_solver = TwoCaptchaSolver(captcha_api_key) self.tracker = DataTracker() # 初始化数据追踪器 self.base_url = "https://my.duoplus.cn" self.api_url = "https://api.duoplus.cn" self.captcha_app_id = None # 生成设备指纹 self.device_fp = self._generate_device_fp() # 设置请求头 self.session.headers.update({ 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/138.0.0.0 Safari/537.36', 'Accept': 'application/json, text/plain, */*', 'Accept-Language': 'zh-CN,zh;q=0.9,en;q=0.8', 'Accept-Encoding': 'gzip, deflate, br', 'Origin': 'https://my.duoplus.cn', 'Referer': 'https://my.duoplus.cn/', 'Content-Type': 'application/json', 'sec-ch-ua': '"Not)A;Brand";v="8", "Chromium";v="138", "Google Chrome";v="138"', 'sec-ch-ua-mobile': '?0', 'sec-ch-ua-platform': '"Windows"', 'sec-fetch-site': 'same-site', 'sec-fetch-mode': 'cors', 'sec-fetch-dest': 'empty', 'pragma': 'no-cache', 'cache-control': 'no-cache', 'lang': 'zh-CN', 'duoplus-fp': self.device_fp, 'priority': 'u=1, i' }) # 获取初始 cookies 和配置 self._init_session() def _generate_device_fp(self) -> str: """生成设备指纹""" # 简单的设备指纹生成,实际可能需要更复杂的算法 random_str = ''.join(random.choices(string.ascii_lowercase + string.digits, k=16)) return hashlib.md5(random_str.encode()).hexdigest() def _init_session(self): """初始化会话,获取必要的 cookies 和配置""" try: # 先访问注册页面获取 cookies response = self.session.get(f"{self.base_url}/sign-up") print(f"{Fore.GREEN}[INFO] 初始化会话成功") # 发送数据追踪请求(模拟真实浏览器行为) self.tracker.track_registration_page() # 获取腾讯验证码配置 self._get_captcha_config() except Exception as e: print(f"{Fore.RED}[ERROR] 初始化会话失败: {str(e)}") def _get_captcha_config(self) -> Optional[Dict[str, Any]]: """ 获取腾讯验证码配置信息 Returns: 验证码配置信息 """ try: # 调用 API 获取验证码配置 config_url = f"{self.api_url}/common/tencentConfig" # 更新请求头中的 referer headers = self.session.headers.copy() headers['referer'] = 'https://my.duoplus.cn/' headers['authorization'] = '' # 注册时可能不需要 authorization response = self.session.get(config_url, headers=headers) if response.status_code == 200: data = response.json() if data.get('code') == 200: self.captcha_app_id = data['data']['captcha_app_id'] print(f"{Fore.GREEN}[INFO] 获取验证码配置成功,app_id: {self.captcha_app_id}") return { "app_id": self.captcha_app_id, "page_url": f"{self.base_url}/sign-up" } else: print(f"{Fore.RED}[ERROR] 获取验证码配置失败: {data.get('message')}") else: print(f"{Fore.RED}[ERROR] 请求验证码配置失败: HTTP {response.status_code}") except Exception as e: print(f"{Fore.RED}[ERROR] 获取验证码配置异常: {str(e)}") # 如果获取失败,返回默认值 return { "app_id": "192789496", # 使用实际的 app_id 作为备份 "page_url": f"{self.base_url}/sign-up" } def send_verification_code(self, email: str) -> bool: """ 发送验证码 Args: email: 邮箱地址 Returns: 是否成功发送 """ print(f"{Fore.CYAN}[INFO] 准备发送验证码到: {email}") # 获取验证码配置 captcha_config = self._get_captcha_config() if not captcha_config: print(f"{Fore.RED}[ERROR] 无法获取验证码配置") return False # 使用 2captcha 解决验证码 print(f"{Fore.YELLOW}[INFO] 正在处理腾讯滑块验证码...") captcha_result = self.captcha_solver.solve_tencent_captcha( app_id=captcha_config["app_id"], page_url=captcha_config["page_url"] ) if not captcha_result: print(f"{Fore.RED}[ERROR] 验证码处理失败") return False # 发送验证码请求 - 使用正确的 API 端点 send_code_url = f"{self.api_url}/email/verificationCode" # 正确的请求体格式 payload = { "type": 1, # 1 表示注册 "email": email, "rand_str": captcha_result["randstr"], "ticket": captcha_result["ticket"] } # 更新请求头 headers = self.session.headers.copy() headers.update({ 'referer': 'https://my.duoplus.cn/', 'authorization': '', 'accept': 'application/json' }) try: print(f"{Fore.YELLOW}[INFO] 发送请求到: {send_code_url}") print(f"{Fore.YELLOW}[DEBUG] 请求体: {json.dumps(payload, ensure_ascii=False)}") response = self.session.post(send_code_url, json=payload, headers=headers) result = response.json() if response.status_code == 200 and result.get("code") == 200: print(f"{Fore.GREEN}[SUCCESS] 验证码发送成功: {result.get('message', 'Success')}") return True else: print(f"{Fore.RED}[ERROR] 发送验证码失败: {result.get('message', 'Unknown error')}") return False except Exception as e: print(f"{Fore.RED}[ERROR] 请求失败: {str(e)}") return False def register(self, email: str, password: str, verification_code: str) -> Dict[str, Any]: """ 执行注册 Args: email: 邮箱地址 password: 密码 verification_code: 邮箱验证码 Returns: 注册结果字典,包含 token 等信息 """ print(f"{Fore.CYAN}[INFO] 开始注册账号...") # 使用正确的注册端点 register_url = f"{self.api_url}/account/signup" # 正确的请求体格式 payload = { "username": email, # 使用邮箱作为用户名 "password": password, "verification_code": verification_code, "isAgress": True, # 同意条款 "from_landing": 0 } # 更新请求头 headers = self.session.headers.copy() headers.update({ 'referer': 'https://my.duoplus.cn/', 'authorization': '', 'accept': 'application/json' }) try: print(f"{Fore.YELLOW}[INFO] 发送注册请求到: {register_url}") print(f"{Fore.YELLOW}[DEBUG] 请求体: {json.dumps(payload, ensure_ascii=False)}") response = self.session.post(register_url, json=payload, headers=headers) result = response.json() if response.status_code == 200 and result.get("code") == 200: print(f"{Fore.GREEN}[SUCCESS] 注册成功!") # 获取返回的数据 data = result.get("data", {}) if data: print(f"{Fore.GREEN}[INFO] Access Token: {data.get('access_token')[:20]}...") print(f"{Fore.GREEN}[INFO] Token 有效期: {data.get('expired_in')} 秒") print(f"{Fore.GREEN}[INFO] 赠送余额: {data.get('gift_balance', '$0.00')}") # 获取用户详细信息 self._get_user_profile(data.get('access_token')) return {"success": True, "data": data} else: print(f"{Fore.RED}[ERROR] 注册失败: {result.get('message', 'Unknown error')}") print(f"{Fore.RED}[DEBUG] 完整响应: {json.dumps(result, ensure_ascii=False)}") return {"success": False, "message": result.get('message')} except Exception as e: print(f"{Fore.RED}[ERROR] 请求失败: {str(e)}") return {"success": False, "message": str(e)} def _get_user_profile(self, access_token: str) -> Optional[Dict[str, Any]]: """ 获取用户详细信息 Args: access_token: 访问令牌 Returns: 用户信息字典 """ profile_url = f"{self.api_url}/account/profile" headers = self.session.headers.copy() headers.update({ 'authorization': access_token, 'accept': 'application/json' }) try: response = self.session.post(profile_url, json={}, headers=headers) result = response.json() if response.status_code == 200 and result.get("code") == 200: profile = result.get("data", {}) print(f"{Fore.GREEN}[INFO] 用户ID: {profile.get('user_id')}") print(f"{Fore.GREEN}[INFO] 邮箱: {profile.get('email')}") print(f"{Fore.GREEN}[INFO] 团队ID: {profile.get('team_id')}") print(f"{Fore.GREEN}[INFO] 团队名称: {profile.get('team_name')}") return profile except Exception as e: print(f"{Fore.YELLOW}[WARNING] 获取用户信息失败: {str(e)}") return None def generate_random_password(self, length: int = 12) -> str: """生成随机密码""" characters = string.ascii_letters + string.digits + "!@#$%^&*" return ''.join(random.choice(characters) for _ in range(length)) def auto_register(self, email: str, password: Optional[str] = None) -> Dict[str, Any]: """ 自动注册流程 Args: email: 邮箱地址 password: 密码(如果不提供则自动生成) Returns: 注册结果字典 """ if not password: password = self.generate_random_password() print(f"{Fore.YELLOW}[INFO] 生成随机密码: {password}") # 保存注册信息 print(f"{Fore.CYAN}{'='*60}") print(f"{Fore.CYAN}注册信息:") print(f"{Fore.CYAN}{'='*60}") print(f" 📧 邮箱: {email}") print(f" 🔑 密码: {password}") print(f"{Fore.CYAN}{'='*60}\n") # 发送验证码 if not self.send_verification_code(email): return {"success": False, "message": "发送验证码失败"} # 等待用户输入验证码 print(f"{Fore.CYAN}[INPUT] 请查看邮箱并输入验证码: ", end="") verification_code = input().strip() # 执行注册 result = self.register(email, password, verification_code) if result.get("success"): # 保存账号信息到文件 self._save_account_info(email, password, result.get("data", {})) return result def auto_register_with_temp_email(self) -> Dict[str, Any]: """ 使用临时邮箱全自动注册 Returns: 注册结果字典 """ print(f"{Fore.CYAN}[INFO] 使用自建邮箱进行全自动注册...") # 创建邮箱管理器 email_manager = EmailManager() auto_verifier = AutoEmailVerification(email_manager) # 创建临时邮箱 print(f"{Fore.CYAN}[INFO] 创建临时邮箱...") email_info = auto_verifier.create_temp_email(domain="cursor.edu.kg") if not email_info.get("success"): return {"success": False, "message": "创建临时邮箱失败"} email_address = email_info["email"] email_password = email_info["password"] print(f"{Fore.GREEN}[INFO] 临时邮箱创建成功") print(f"{Fore.GREEN}[INFO] 邮箱: {email_address}") print(f"{Fore.GREEN}[INFO] 邮箱密码: {email_password}") # 生成DuoPlus账号密码 duoplus_password = self.generate_random_password() # 保存注册信息 print(f"\n{Fore.CYAN}{'='*60}") print(f"{Fore.CYAN}DuoPlus 注册信息:") print(f"{Fore.CYAN}{'='*60}") print(f" 📧 邮箱: {email_address}") print(f" 🔑 密码: {duoplus_password}") print(f"{Fore.CYAN}{'='*60}\n") # 发送验证码 if not self.send_verification_code(email_address): return {"success": False, "message": "发送验证码失败"} # 自动获取验证码 print(f"{Fore.CYAN}[INFO] 等待接收验证码...") verification_code = auto_verifier.wait_for_code( email_info, sender_filter="duoplus", timeout=60 ) if not verification_code: print(f"{Fore.YELLOW}[WARNING] 自动获取验证码失败,请手动输入") print(f"{Fore.CYAN}[INPUT] 请输入验证码: ", end="") verification_code = input().strip() # 执行注册 result = self.register(email_address, duoplus_password, verification_code) if result.get("success"): # 保存账号信息到文件,包括邮箱密码 data = result.get("data", {}) data["email_password"] = email_password # 保存邮箱密码 self._save_account_info(email_address, duoplus_password, data) return result def _save_account_info(self, email: str, password: str, data: Dict[str, Any]): """ 保存账号信息到文件 Args: email: 邮箱 password: 密码 data: 注册返回的数据 """ try: import datetime filename = "registered_accounts.txt" with open(filename, "a", encoding="utf-8") as f: f.write(f"\n{'='*60}\n") f.write(f"注册时间: {datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')}\n") f.write(f"邮箱: {email}\n") f.write(f"密码: {password}\n") f.write(f"Access Token: {data.get('access_token', 'N/A')}\n") f.write(f"Refresh Token: {data.get('refresh_token', 'N/A')}\n") f.write(f"Token 有效期: {data.get('expired_in', 0)} 秒\n") f.write(f"赠送余额: {data.get('gift_balance', '$0.00')}\n") print(f"{Fore.GREEN}[INFO] 账号信息已保存到 {filename}") except Exception as e: print(f"{Fore.YELLOW}[WARNING] 保存账号信息失败: {str(e)}") def main(): # 加载环境变量 load_dotenv() # 获取 API Key captcha_api_key = os.getenv('CAPTCHA_API_KEY') if not captcha_api_key: print(f"{Fore.RED}[ERROR] 请在 .env 文件中设置 CAPTCHA_API_KEY") return # 创建注册器 registrar = DuoPlusRegister(captcha_api_key) # 获取用户输入 print(f"{Fore.CYAN}=== DuoPlus 自动注册工具 ===") email = input(f"{Fore.YELLOW}请输入邮箱地址: ").strip() use_random_password = input(f"{Fore.YELLOW}是否使用随机密码? (y/n): ").strip().lower() == 'y' if use_random_password: password = None else: password = input(f"{Fore.YELLOW}请输入密码: ").strip() # 执行注册 if registrar.auto_register(email, password): print(f"{Fore.GREEN}[SUCCESS] 注册流程完成!") else: print(f"{Fore.RED}[FAILED] 注册失败!") if __name__ == "__main__": main()