cursor_pro_keep_alive.py 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439
  1. import os
  2. import sys
  3. from enum import Enum
  4. from typing import Optional
  5. from exit_cursor import ExitCursor
  6. from reset_machine import MachineIDResetter
  7. os.environ["PYTHONVERBOSE"] = "0"
  8. os.environ["PYINSTALLER_VERBOSE"] = "0"
  9. import time
  10. import random
  11. from cursor_auth_manager import CursorAuthManager
  12. import os
  13. from logger import logging
  14. from browser_utils import BrowserManager
  15. from get_email_code import EmailVerificationHandler
  16. from logo import print_logo
  17. from config import Config
  18. # 定义 EMOJI 字典
  19. EMOJI = {"ERROR": "❌", "WARNING": "⚠️", "INFO": "ℹ️"}
  20. class VerificationStatus(Enum):
  21. """验证状态枚举"""
  22. PASSWORD_PAGE = "@name=password"
  23. CAPTCHA_PAGE = "@data-index=0"
  24. ACCOUNT_SETTINGS = "Account Settings"
  25. class TurnstileError(Exception):
  26. """Turnstile 验证相关异常"""
  27. pass
  28. def save_screenshot(tab, stage: str, timestamp: bool = True) -> None:
  29. """
  30. 保存页面截图
  31. Args:
  32. tab: 浏览器标签页对象
  33. stage: 截图阶段标识
  34. timestamp: 是否添加时间戳
  35. """
  36. try:
  37. # 创建 screenshots 目录
  38. screenshot_dir = "screenshots"
  39. if not os.path.exists(screenshot_dir):
  40. os.makedirs(screenshot_dir)
  41. # 生成文件名
  42. if timestamp:
  43. filename = f"turnstile_{stage}_{int(time.time())}.png"
  44. else:
  45. filename = f"turnstile_{stage}.png"
  46. filepath = os.path.join(screenshot_dir, filename)
  47. # 保存截图
  48. tab.get_screenshot(filepath)
  49. logging.debug(f"截图已保存: {filepath}")
  50. except Exception as e:
  51. logging.warning(f"截图保存失败: {str(e)}")
  52. def check_verification_success(tab) -> Optional[VerificationStatus]:
  53. """
  54. 检查验证是否成功
  55. Returns:
  56. VerificationStatus: 验证成功时返回对应状态,失败返回 None
  57. """
  58. for status in VerificationStatus:
  59. if tab.ele(status.value):
  60. logging.info(f"验证成功 - 已到达{status.name}页面")
  61. return status
  62. return None
  63. def handle_turnstile(tab, max_retries: int = 2, retry_interval: tuple = (1, 2)) -> bool:
  64. """
  65. 处理 Turnstile 验证
  66. Args:
  67. tab: 浏览器标签页对象
  68. max_retries: 最大重试次数
  69. retry_interval: 重试间隔时间范围(最小值, 最大值)
  70. Returns:
  71. bool: 验证是否成功
  72. Raises:
  73. TurnstileError: 验证过程中出现异常
  74. """
  75. logging.info("正在检测 Turnstile 验证...")
  76. save_screenshot(tab, "start")
  77. retry_count = 0
  78. try:
  79. while retry_count < max_retries:
  80. retry_count += 1
  81. logging.debug(f"第 {retry_count} 次尝试验证")
  82. try:
  83. # 定位验证框元素
  84. challenge_check = (
  85. tab.ele("@id=cf-turnstile", timeout=2)
  86. .child()
  87. .shadow_root.ele("tag:iframe")
  88. .ele("tag:body")
  89. .sr("tag:input")
  90. )
  91. if challenge_check:
  92. logging.info("检测到 Turnstile 验证框,开始处理...")
  93. # 随机延时后点击验证
  94. time.sleep(random.uniform(1, 3))
  95. challenge_check.click()
  96. time.sleep(2)
  97. # 保存验证后的截图
  98. save_screenshot(tab, "clicked")
  99. # 检查验证结果
  100. if check_verification_success(tab):
  101. logging.info("Turnstile 验证通过")
  102. save_screenshot(tab, "success")
  103. return True
  104. except Exception as e:
  105. logging.debug(f"当前尝试未成功: {str(e)}")
  106. # 检查是否已经验证成功
  107. if check_verification_success(tab):
  108. return True
  109. # 随机延时后继续下一次尝试
  110. time.sleep(random.uniform(*retry_interval))
  111. # 超出最大重试次数
  112. logging.error(f"验证失败 - 已达到最大重试次数 {max_retries}")
  113. save_screenshot(tab, "failed")
  114. return False
  115. except Exception as e:
  116. error_msg = f"Turnstile 验证过程发生异常: {str(e)}"
  117. logging.error(error_msg)
  118. save_screenshot(tab, "error")
  119. raise TurnstileError(error_msg)
  120. def get_cursor_session_token(tab, max_attempts=3, retry_interval=2):
  121. """
  122. 获取Cursor会话token,带有重试机制
  123. :param tab: 浏览器标签页
  124. :param max_attempts: 最大尝试次数
  125. :param retry_interval: 重试间隔(秒)
  126. :return: session token 或 None
  127. """
  128. logging.info("开始获取cookie")
  129. attempts = 0
  130. while attempts < max_attempts:
  131. try:
  132. cookies = tab.cookies()
  133. for cookie in cookies:
  134. if cookie.get("name") == "WorkosCursorSessionToken":
  135. return cookie["value"].split("%3A%3A")[1]
  136. attempts += 1
  137. if attempts < max_attempts:
  138. logging.warning(
  139. f"第 {attempts} 次尝试未获取到CursorSessionToken,{retry_interval}秒后重试..."
  140. )
  141. time.sleep(retry_interval)
  142. else:
  143. logging.error(
  144. f"已达到最大尝试次数({max_attempts}),获取CursorSessionToken失败"
  145. )
  146. except Exception as e:
  147. logging.error(f"获取cookie失败: {str(e)}")
  148. attempts += 1
  149. if attempts < max_attempts:
  150. logging.info(f"将在 {retry_interval} 秒后重试...")
  151. time.sleep(retry_interval)
  152. return None
  153. def update_cursor_auth(email=None, access_token=None, refresh_token=None):
  154. """
  155. 更新Cursor的认证信息的便捷函数
  156. """
  157. auth_manager = CursorAuthManager()
  158. return auth_manager.update_auth(email, access_token, refresh_token)
  159. def sign_up_account(browser, tab):
  160. logging.info("=== 开始注册账号流程 ===")
  161. logging.info(f"正在访问注册页面: {sign_up_url}")
  162. tab.get(sign_up_url)
  163. try:
  164. if tab.ele("@name=first_name"):
  165. logging.info("正在填写个人信息...")
  166. tab.actions.click("@name=first_name").input(first_name)
  167. logging.info(f"已输入名字: {first_name}")
  168. time.sleep(random.uniform(1, 3))
  169. tab.actions.click("@name=last_name").input(last_name)
  170. logging.info(f"已输入姓氏: {last_name}")
  171. time.sleep(random.uniform(1, 3))
  172. tab.actions.click("@name=email").input(account)
  173. logging.info(f"已输入邮箱: {account}")
  174. time.sleep(random.uniform(1, 3))
  175. logging.info("提交个人信息...")
  176. tab.actions.click("@type=submit")
  177. except Exception as e:
  178. logging.error(f"注册页面访问失败: {str(e)}")
  179. return False
  180. handle_turnstile(tab)
  181. try:
  182. if tab.ele("@name=password"):
  183. logging.info("正在设置密码...")
  184. tab.ele("@name=password").input(password)
  185. time.sleep(random.uniform(1, 3))
  186. logging.info("提交密码...")
  187. tab.ele("@type=submit").click()
  188. logging.info("密码设置完成,等待系统响应...")
  189. except Exception as e:
  190. logging.error(f"密码设置失败: {str(e)}")
  191. return False
  192. time.sleep(random.uniform(1, 3))
  193. if tab.ele("This email is not available."):
  194. logging.error("注册失败:邮箱已被使用")
  195. return False
  196. handle_turnstile(tab)
  197. while True:
  198. try:
  199. if tab.ele("Account Settings"):
  200. logging.info("注册成功 - 已进入账户设置页面")
  201. break
  202. if tab.ele("@data-index=0"):
  203. logging.info("正在获取邮箱验证码...")
  204. code = email_handler.get_verification_code(account)
  205. if not code:
  206. logging.error("获取验证码失败")
  207. return False
  208. logging.info(f"成功获取验证码: {code}")
  209. logging.info("正在输入验证码...")
  210. i = 0
  211. for digit in code:
  212. tab.ele(f"@data-index={i}").input(digit)
  213. time.sleep(random.uniform(0.1, 0.3))
  214. i += 1
  215. logging.info("验证码输入完成")
  216. break
  217. except Exception as e:
  218. logging.error(f"验证码处理过程出错: {str(e)}")
  219. handle_turnstile(tab)
  220. wait_time = random.randint(3, 6)
  221. for i in range(wait_time):
  222. logging.info(f"等待系统处理中... 剩余 {wait_time-i} 秒")
  223. time.sleep(1)
  224. logging.info("正在获取账户信息...")
  225. tab.get(settings_url)
  226. try:
  227. usage_selector = (
  228. "css:div.col-span-2 > div > div > div > div > "
  229. "div:nth-child(1) > div.flex.items-center.justify-between.gap-2 > "
  230. "span.font-mono.text-sm\\/\\[0\\.875rem\\]"
  231. )
  232. usage_ele = tab.ele(usage_selector)
  233. if usage_ele:
  234. usage_info = usage_ele.text
  235. total_usage = usage_info.split("/")[-1].strip()
  236. logging.info(f"账户可用额度上限: {total_usage}")
  237. else:
  238. logging.error("无法获取账户额度信息")
  239. return False
  240. except Exception as e:
  241. logging.error(f"获取账户额度信息失败: {str(e)}")
  242. logging.info("\n=== 注册完成 ===")
  243. account_info = f"Cursor 账号信息:\n邮箱: {account}\n密码: {password}"
  244. logging.info(account_info)
  245. time.sleep(5)
  246. return True
  247. class EmailGenerator:
  248. def __init__(
  249. self,
  250. password="".join(
  251. random.choices(
  252. "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!@#$%^&*",
  253. k=12,
  254. )
  255. ),
  256. ):
  257. configInstance = Config()
  258. configInstance.print_config()
  259. self.default_password = password
  260. self.default_first_name = self.generate_random_name()
  261. self.default_last_name = self.generate_random_name()
  262. def generate_random_name(self, length=6):
  263. """生成随机用户名"""
  264. first_letter = random.choice("ABCDEFGHIJKLMNOPQRSTUVWXYZ")
  265. rest_letters = "".join(
  266. random.choices("abcdefghijklmnopqrstuvwxyz", k=length - 1)
  267. )
  268. return first_letter + rest_letters
  269. def generate_email(self, length=8):
  270. """获取可用的邮箱地址"""
  271. try:
  272. email_handler = EmailVerificationHandler()
  273. email_handler._create_mailbox()
  274. email_list = email_handler._get_email_list()
  275. if email_list and len(email_list) > 0:
  276. return email_list[-1] # 直接返回最后一个邮箱地址
  277. raise Exception("无法获取可用的邮箱地址")
  278. except Exception as e:
  279. logging.error(f"获取邮箱地址失败: {str(e)}")
  280. raise
  281. def get_account_info(self):
  282. """获取完整的账号信息"""
  283. return {
  284. "email": self.generate_email(),
  285. "password": self.default_password,
  286. "first_name": self.default_first_name,
  287. "last_name": self.default_last_name,
  288. }
  289. if __name__ == "__main__":
  290. print_logo()
  291. browser_manager = None
  292. try:
  293. logging.info("\n=== 初始化程序 ===")
  294. ExitCursor()
  295. # 提示用户选择操作模式
  296. print("\n请选择操作模式:")
  297. print("1. 仅重置机器码")
  298. print("2. 完整注册流程")
  299. while True:
  300. try:
  301. choice = int(input("请输入选项 (1 或 2): ").strip())
  302. if choice in [1, 2]:
  303. break
  304. else:
  305. print("无效的选项,请重新输入")
  306. except ValueError:
  307. print("请输入有效的数字")
  308. if choice == 1:
  309. # 仅执行重置机器码
  310. logging.info("正在重置机器码...")
  311. MachineIDResetter().reset_machine_ids()
  312. logging.info("机器码重置完成")
  313. sys.exit(0)
  314. # 如果选择2,继续执行完整注册流程
  315. logging.info("正在初始化浏览器...")
  316. browser_manager = BrowserManager()
  317. browser = browser_manager.init_browser()
  318. logging.info("正在初始化邮箱验证模块...")
  319. email_handler = EmailVerificationHandler()
  320. logging.info("\n=== 配置信息 ===")
  321. login_url = "https://authenticator.cursor.sh"
  322. sign_up_url = "https://authenticator.cursor.sh/sign-up"
  323. settings_url = "https://www.cursor.com/settings"
  324. logging.info("正在生成随机账号信息...")
  325. email_generator = EmailGenerator()
  326. account = email_generator.generate_email()
  327. password = email_generator.default_password
  328. first_name = email_generator.default_first_name
  329. last_name = email_generator.default_last_name
  330. logging.info(f"生成的邮箱账号: {account}")
  331. auto_update_cursor_auth = True
  332. tab = browser.latest_tab
  333. tab.run_js("try { turnstile.reset() } catch(e) { }")
  334. logging.info("\n=== 开始注册流程 ===")
  335. logging.info(f"正在访问登录页面: {login_url}")
  336. tab.get(login_url)
  337. if sign_up_account(browser, tab):
  338. logging.info("正在获取会话令牌...")
  339. token = get_cursor_session_token(tab)
  340. if token:
  341. logging.info("更新认证信息...")
  342. update_cursor_auth(
  343. email=account, access_token=token, refresh_token=token
  344. )
  345. logging.info("重置机器码...")
  346. MachineIDResetter().reset_machine_ids()
  347. logging.info("所有操作已完成")
  348. else:
  349. logging.error("获取会话令牌失败,注册流程未完成")
  350. except Exception as e:
  351. logging.error(f"程序执行出现错误: {str(e)}")
  352. import traceback
  353. logging.error(traceback.format_exc())
  354. finally:
  355. if browser_manager:
  356. browser_manager.quit()
  357. input("\n程序执行完毕,按回车键退出...")