commit d48b1a9d6d59682890d60ee4a49f05dd16c6f703 Author: chengchongzhen <15939054361@163.com> Date: Sat Dec 28 15:14:40 2024 +0800 Add initial implementation of Cursor Pro Keep Alive tool - Created .gitignore to exclude unnecessary files. - Added config.ini for account configuration. - Implemented cursor_auth_manager.py for managing authentication. - Developed cursor_pro_keep_alive.py for automated account management. - Included CursorKeepAlive.spec for packaging. - Added gpt-accesstoken.py for obtaining ChatGPT access tokens. - Created README.md with usage instructions. - Updated requirements.txt with necessary dependencies. - Added run_cursor.bat for script execution. - Implemented update_cursor_auth.py for updating authentication details. - Included turnstilePatch for handling CAPTCHA challenges. - Added logging functionality in log.txt for tracking script execution. - Created dist folder with packaged executable and necessary files. diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..47fdc31 --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +.idea +__pycache__ + +build \ No newline at end of file diff --git a/CursorKeepAlive.spec b/CursorKeepAlive.spec new file mode 100644 index 0000000..ab1c074 --- /dev/null +++ b/CursorKeepAlive.spec @@ -0,0 +1,42 @@ +# -*- mode: python ; coding: utf-8 -*- + +a = Analysis( + ['cursor_pro_keep_alive.py'], + pathex=[], + binaries=[], + datas=[ + ('config.ini', '.'), + ('turnstilePatch', 'turnstilePatch'), + ('cursor_auth_manager.py', '.'), + ], + hiddenimports=[ + 'cursor_auth_manager' + ], + hookspath=[], + hooksconfig={}, + runtime_hooks=[], + excludes=[], + noarchive=False, +) +pyz = PYZ(a.pure) + +exe = EXE( + pyz, + a.scripts, + a.binaries, + a.datas, + [], + name='cursor_pro_keep_alive', + debug=False, + bootloader_ignore_signals=False, + strip=False, + upx=True, + upx_exclude=[], + runtime_tmpdir=None, + console=True, + disable_windowed_traceback=False, + argv_emulation=False, + target_arch=None, + codesign_identity=None, + entitlements_file=None, +) diff --git a/README.md b/README.md new file mode 100644 index 0000000..feb1b7b --- /dev/null +++ b/README.md @@ -0,0 +1,5 @@ +# gpt-cursor-auto +Python脚本 一键获取 ChatGpt 的 Access Token -- gpt-accesstoken.py +*********************************************************************************************** +Python脚本 一键获取 Cursor Pro 自动保活 -- cursor_pro_keep_alive.py +2024.12.14日 新增自动获取token,无需再手动登录账号关联Cursor,需要 依赖 cursor_auth_manager.py diff --git a/config.ini b/config.ini new file mode 100644 index 0000000..a063651 --- /dev/null +++ b/config.ini @@ -0,0 +1,5 @@ +[Account] +email = apxeme@mailto.plus +password = ccz14321@ +first_name = cheng +last_name = zhen \ No newline at end of file diff --git a/cursor_auth_manager.py b/cursor_auth_manager.py new file mode 100644 index 0000000..0060baf --- /dev/null +++ b/cursor_auth_manager.py @@ -0,0 +1,60 @@ +import sqlite3 +import os + +class CursorAuthManager: + """Cursor认证信息管理器""" + + def __init__(self): + # 判断操作系统 + if os.name == 'nt': # Windows + self.db_path = os.path.join(os.getenv('APPDATA'), 'Cursor', 'User', 'globalStorage', 'state.vscdb') + else: # macOS + self.db_path = os.path.expanduser('~/Library/Application Support/Cursor/User/globalStorage/state.vscdb') + + + def update_auth(self, email=None, access_token=None, refresh_token=None): + """ + 更新Cursor的认证信息 + :param email: 新的邮箱地址 + :param access_token: 新的访问令牌 + :param refresh_token: 新的刷新令牌 + :return: bool 是否成功更新 + """ + updates = [] + if email is not None: + updates.append(('cursorAuth/cachedEmail', email)) + if access_token is not None: + updates.append(('cursorAuth/accessToken', access_token)) + if refresh_token is not None: + updates.append(('cursorAuth/refreshToken', refresh_token)) + + if not updates: + print("没有提供任何要更新的值") + return False + + conn = None + try: + conn = sqlite3.connect(self.db_path) + cursor = conn.cursor() + + for key, value in updates: + query = "UPDATE itemTable SET value = ? WHERE key = ?" + cursor.execute(query, (value, key)) + + if cursor.rowcount > 0: + print(f"成功更新 {key.split('/')[-1]}") + else: + print(f"未找到 {key.split('/')[-1]} 或值未变化") + + conn.commit() + return True + + except sqlite3.Error as e: + print("数据库错误:", str(e)) + return False + except Exception as e: + print("发生错误:", str(e)) + return False + finally: + if conn: + conn.close() diff --git a/cursor_pro_keep_alive.py b/cursor_pro_keep_alive.py new file mode 100644 index 0000000..f32a7e9 --- /dev/null +++ b/cursor_pro_keep_alive.py @@ -0,0 +1,453 @@ +from DrissionPage import ChromiumOptions, Chromium +from DrissionPage.common import Keys +import re +import time +import random +from cursor_auth_manager import CursorAuthManager +from configparser import ConfigParser +import os +import sys + + +def load_config(): + """加载配置文件""" + config = ConfigParser() + + # 获取程序运行的根目录 + root_dir = os.getcwd() + config_path = os.path.join(root_dir, "config.ini") + + if os.path.exists(config_path): + config.read(config_path, encoding="utf-8") + print(f"已加载配置文件: {config_path}") + return { + "account": config["Account"]["email"], + "password": config["Account"]["password"], + "first_name": config["Account"]["first_name"], + "last_name": config["Account"]["last_name"], + } + + raise FileNotFoundError( + f"配置文件不存在: {config_path}\n请确保配置文件在程序运行目录下" + ) + + +def get_veri_code(tab): + """获取验证码""" + username = account.split("@")[0] + try: + while True: + if tab.ele("@id=pre_button"): + tab.actions.click("@id=pre_button").type(Keys.CTRL_A).key_down( + Keys.BACKSPACE + ).key_up(Keys.BACKSPACE).input(username).key_down(Keys.ENTER).key_up( + Keys.ENTER + ) + break + time.sleep(1) + + while True: + new_mail = tab.ele("@class=mail") + if new_mail: + if new_mail.text: + print("最新的邮件:", new_mail.text) + tab.actions.click("@class=mail") + break + else: + print(new_mail) + break + time.sleep(1) + + if tab.ele("@class=overflow-auto mb-20"): + email_content = tab.ele("@class=overflow-auto mb-20").text + verification_code = re.search( + r"verification code is (\d{6})", email_content + ) + if verification_code: + code = verification_code.group(1) + print("验证码:", code) + else: + print("未找到验证码") + + if tab.ele("@id=delete_mail"): + tab.actions.click("@id=delete_mail") + time.sleep(1) + + if tab.ele("@id=confirm_mail"): + tab.actions.click("@id=confirm_mail") + print("删除邮件") + tab.close() + except Exception as e: + print(e) + + return code + + +def handle_turnstile(tab): + """处理 Turnstile 验证""" + print("准备处理验证") + try: + while True: + try: + challengeCheck = ( + tab.ele("@id=cf-turnstile", timeout=2) + .child() + .shadow_root.ele("tag:iframe") + .ele("tag:body") + .sr("tag:input") + ) + + if challengeCheck: + print("验证框加载完成") + time.sleep(random.uniform(1, 3)) + challengeCheck.click() + print("验证按钮已点击,等待验证完成...") + time.sleep(2) + return True + except: + pass + + if tab.ele("@name=password"): + print("无需验证") + break + if tab.ele("@data-index=0"): + print("无需验证") + break + if tab.ele("Account Settings"): + print("无需验证") + break + + time.sleep(random.uniform(1, 2)) + except Exception as e: + print(e) + print("跳过验证") + return False + + +def delete_account(browser, tab): + """删除账户流程""" + print("\n开始删除账户...") + + try: + if tab.ele("@name=email"): + tab.ele("@name=email").input(account) + print("输入账号") + time.sleep(random.uniform(1, 3)) + except Exception as e: + print(f"输入账号失败: {str(e)}") + + try: + if tab.ele("Continue"): + tab.ele("Continue").click() + print("点击Continue") + except Exception as e: + print(f"点击Continue失败: {str(e)}") + + handle_turnstile(tab) + time.sleep(5) + + try: + if tab.ele("@name=password"): + tab.ele("@name=password").input(password) + print("输入密码") + time.sleep(random.uniform(1, 3)) + except Exception as e: + print("输入密码失败") + + sign_in_button = tab.ele( + "xpath:/html/body/div[1]/div/div/div[2]/div/form/div/button" + ) + try: + if sign_in_button: + sign_in_button.click(by_js=True) + print("点击Sign in") + except Exception as e: + print(f"点击Sign in失败: {str(e)}") + + handle_turnstile(tab) + + # 处理验证码 + while True: + try: + if tab.ele("Account Settings"): + break + if tab.ele("@data-index=0"): + tab_mail = browser.new_tab(mail_url) + browser.activate_tab(tab_mail) + print("打开邮箱页面") + code = get_veri_code(tab_mail) + + if code: + print("获取验证码成功:", code) + browser.activate_tab(tab) + else: + print("获取验证码失败,程序退出") + return False + + i = 0 + for digit in code: + tab.ele(f"@data-index={i}").input(digit) + time.sleep(random.uniform(0.1, 0.3)) + i += 1 + break + except Exception as e: + print(e) + + handle_turnstile(tab) + time.sleep(random.uniform(1, 3)) + # tab.get_screenshot('sign-in_success.png') + # print("登录账户截图") + + tab.get(settings_url) + print("进入设置页面") + + try: + if tab.ele("@class=mt-1"): + tab.ele("@class=mt-1").click() + print("点击Adavance") + time.sleep(random.uniform(1, 2)) + except Exception as e: + print(f"点击Adavance失败: {str(e)}") + + try: + if tab.ele("Delete Account"): + tab.ele("Delete Account").click() + print("点击Delete Account") + time.sleep(random.uniform(1, 2)) + except Exception as e: + print(f"点击Delete Account失败: {str(e)}") + + try: + if tab.ele("tag:input"): + tab.actions.click("tag:input").type("delete") + print("输入delete") + time.sleep(random.uniform(1, 2)) + except Exception as e: + print(f"输入delete失败: {str(e)}") + + delete_button = tab.ele( + "xpath:/html/body/main/div/div/div/div/div/div[1]/div[2]/div[3]/div[2]/div/div/div[2]/button[2]" + ) + try: + if delete_button: + print("点击Delete") + delete_button.click() + time.sleep(5) + # tab.get_screenshot('delete_account.png') + # print("删除账户截图") + return True + except Exception as e: + print(f"点击Delete失败: {str(e)}") + return False + + +def get_cursor_session_token(tab): + """获取cursor session token""" + cookies = tab.cookies() + cursor_session_token = None + for cookie in cookies: + if cookie["name"] == "WorkosCursorSessionToken": + cursor_session_token = cookie["value"].split("%3A%3A")[1] + break + return cursor_session_token + + +def update_cursor_auth(email=None, access_token=None, refresh_token=None): + """ + 更新Cursor的认证信息的便捷函数 + """ + auth_manager = CursorAuthManager() + return auth_manager.update_auth(email, access_token, refresh_token) + + +def sign_up_account(browser, tab): + """注册账户流程""" + print("\n开始注册新账户...") + tab.get(sign_up_url) + + try: + if tab.ele("@name=first_name"): + print("已打开注册页面") + tab.actions.click("@name=first_name").input(first_name) + time.sleep(random.uniform(1, 3)) + + tab.actions.click("@name=last_name").input(last_name) + time.sleep(random.uniform(1, 3)) + + tab.actions.click("@name=email").input(account) + print("输入邮箱") + time.sleep(random.uniform(1, 3)) + + tab.actions.click("@type=submit") + print("点击注册按钮") + + except Exception as e: + print("打开注册页面失败") + return False + + handle_turnstile(tab) + + try: + if tab.ele("@name=password"): + tab.ele("@name=password").input(password) + print("输入密码") + time.sleep(random.uniform(1, 3)) + + tab.ele("@type=submit").click() + print("点击Continue按钮") + + except Exception as e: + print("输入密码失败") + return False + + time.sleep(random.uniform(1, 3)) + if tab.ele("This email is not available."): + print("This email is not available.") + return False + + handle_turnstile(tab) + + while True: + try: + if tab.ele("Account Settings"): + break + if tab.ele("@data-index=0"): + tab_mail = browser.new_tab(mail_url) + browser.activate_tab(tab_mail) + print("打开邮箱页面") + code = get_veri_code(tab_mail) + + if code: + print("获取验证码成功:", code) + browser.activate_tab(tab) + else: + print("获取验证码失败,程序退出") + return False + + i = 0 + for digit in code: + tab.ele(f"@data-index={i}").input(digit) + time.sleep(random.uniform(0.1, 0.3)) + i += 1 + break + except Exception as e: + print(e) + + handle_turnstile(tab) + + time.sleep(random.uniform(1, 3)) + print("进入设置页面") + tab.get(settings_url) + try: + usage_ele = tab.ele( + "xpath:/html/body/main/div/div/div/div/div/div[2]/div/div/div/div[1]/div[1]/span[2]" + ) + if usage_ele: + usage_info = usage_ele.text + total_usage = usage_info.split("/")[-1].strip() + print("可用上限: " + total_usage) + except Exception as e: + print("获取可用上限失败") + # tab.get_screenshot("sign_up_success.png") + # print("注册账户截图") + print("注册完成") + print("Cursor 账号: " + account) + print(" 密码: " + password) + return True + + +def get_extension_path(): + """获取插件路径""" + root_dir = os.getcwd() + extension_path = os.path.join(root_dir, "turnstilePatch") + + if hasattr(sys, "_MEIPASS"): + print("运行在打包环境中") + extension_path = os.path.join(sys._MEIPASS, "turnstilePatch") + + print(f"尝试加载插件路径: {extension_path}") + + if not os.path.exists(extension_path): + raise FileNotFoundError( + f"插件不存在: {extension_path}\n请确保 turnstilePatch 文件夹在正确位置" + ) + + return extension_path + + +if __name__ == "__main__": + try: + # 加载配置 + config = load_config() + + # 固定的 URL 配置 + login_url = "https://authenticator.cursor.sh" + sign_up_url = "https://authenticator.cursor.sh/sign-up" + settings_url = "https://www.cursor.com/settings" + mail_url = "https://tempmail.plus" + + # 账号信息 + account = config["account"] + password = config["password"] + first_name = config["first_name"] + last_name = config["last_name"] + + auto_update_cursor_auth = True + + # 浏览器配置 + co = ChromiumOptions() + try: + extension_path = get_extension_path() + co.add_extension(extension_path) + except FileNotFoundError as e: + print(f"警告: {e}") + print("将尝试继续执行...") + + co.headless() # 无头模式 + co.set_user_agent( + "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.6723.92 Safari/537.36" + ) + co.set_pref("credentials_enable_service", False) + co.set_argument("--hide-crash-restore-bubble") + co.auto_port() + # co.set_argument('--no-sandbox') # 无沙盒模式 用于linux + # co.set_argument('--headless=new') #无界面系统启动参数 用于linux + # co.set_proxy('127.0.0.1:10809') #设置代理 + + browser = Chromium(co) + tab = browser.latest_tab + tab.run_js("try { turnstile.reset() } catch(e) { }") + + print("开始执行删除和注册流程") + print("***请确认已经用https://tempmail.plus/zh邮箱成功申请过cursor账号!***") + tab.get(login_url) + + # 执行删除和注册流程 + if delete_account(browser, tab): + print("账户删除成功") + time.sleep(3) + if sign_up_account(browser, tab): + token = get_cursor_session_token(tab) + print(f"CursorSessionToken: {token}") + print("账户注册成功") + if auto_update_cursor_auth: + update_cursor_auth( + email=account, access_token=token, refresh_token=token + ) + else: + print("账户注册失败") + else: + print("账户删除失败") + + print("脚本执行完毕") + browser.quit() + + # 添加等待用户输入后再退出 + input("\n按回车键退出...") + except FileNotFoundError as e: + print(f"���误: {e}") + print("请确保 config.ini 文件存在并包含正确的配置信息") + input("\n按回车键退出...") + except Exception as e: + print(f"加载配置时出错: {e}") + input("\n按回车键退出...") diff --git a/dist/config - 副本.ini b/dist/config - 副本.ini new file mode 100644 index 0000000..887fc44 --- /dev/null +++ b/dist/config - 副本.ini @@ -0,0 +1,5 @@ +[Account] +email = xxxx +password = xxx +first_name = xxxx +last_name = xxxx diff --git a/dist/config.ini b/dist/config.ini new file mode 100644 index 0000000..a063651 --- /dev/null +++ b/dist/config.ini @@ -0,0 +1,5 @@ +[Account] +email = apxeme@mailto.plus +password = ccz14321@ +first_name = cheng +last_name = zhen \ No newline at end of file diff --git a/dist/cursor_pro_keep_alive.exe b/dist/cursor_pro_keep_alive.exe new file mode 100644 index 0000000..ec7836a Binary files /dev/null and b/dist/cursor_pro_keep_alive.exe differ diff --git a/dist/readme.md b/dist/readme.md new file mode 100644 index 0000000..e18c662 --- /dev/null +++ b/dist/readme.md @@ -0,0 +1,95 @@ + + +# Cursor Pro Keep Alive 使用说明文档 + +## 1. 软件介绍 +Cursor Pro Keep Alive 是一个自动化工具,用于管理 Cursor 账号的注册和更新。该工具可以自动执行账号删除和重新注册流程,以保持账号活跃。 + +## 2. 安装和准备 + +### 2.1 必要文件 +确保您有以下文件: +- `cursor_pro_keep_alive.exe` - 主程序 +- `config.ini` - 配置文件 +- `turnstilePatch` - 插件文件夹 + +### 2.2 文件结构 +``` +your_folder/ +├── cursor_pro_keep_alive.exe +├── config.ini +└── turnstilePatch/ + └── (插件文件) +``` + +## 3. 配置文件设置 + +在运行程序前,需要正确配置 `config.ini` 文件: + +```ini +[Account] +email = your_username@mailto.plus # 邮箱地址(必须使用 mailto.plus 域名) +password = your_password # 账号密码 +first_name = your_firstname # 名字 +last_name = your_lastname # 姓氏 +``` + +注意事项: +- 邮箱必须使用 `mailto.plus` 域名 +- 请确保配置文件使用 UTF-8 编码保存 + +## 4. 运行程序 + +### 4.1 运行步骤 +1. 确保所有必要文件都在同一目录下 +2. 双击运行 `cursor_pro_keep_alive.exe` +3. 程序会自动执行以下操作: + - 删除现有账号 + - 注册新账号 + - 更新认证信息 + +### 4.2 运行提示 +- 程序运行过程中会显示各个步骤的执行状态 +- 如果出现验证码,程序会自动处理 +- 运行完成后会显示操作结果 + +## 5. 常见问题解决 + +### 5.1 配置文件错误 +错误提示:`配置文件不存在` +- 解决方法:确保 `config.ini` 文件在程序同目录下 + +### 5.2 插件加载失败 +错误提示:`插件不存在` +- 解决方法:确保 `turnstilePatch` 文件夹在程序同目录下 +- 注意:即使插件加载失败,程序仍会继续执行 + +### 5.3 账号注册失败 +- 检查邮箱格式是否正确(必须是 mailto.plus) +- 确保密码符合要求 +- 检查网络连接是否正常 + +## 6. 注意事项 + +1. 运行环境要求: + - Windows 操作系统 + - 稳定的网络连接 + +2. 安全提示: + - 请妥善保管配置文件,避免泄露账号信息 + - 建议定期更改密码 + +3. 使用建议: + - 建议在非高峰时段运行程序 + - 保持配置文件的定期备份 + +## 7. 技术支持 + +如遇到问题,请检查: +1. 配置文件格式是否正确 +2. 必要文件是否完整 +3. 网络连接是否正常 + +## 8. 免责声明 + +本程序仅供学习和研究使用,请遵守相关服务条款和法律法规。使用本程序产生的任何后果由用户自行承担。 diff --git a/gpt-accesstoken.py b/gpt-accesstoken.py new file mode 100644 index 0000000..4f8bbf8 --- /dev/null +++ b/gpt-accesstoken.py @@ -0,0 +1,166 @@ +from DrissionPage import ChromiumOptions, Chromium +import random +import time + +def handle_turnstile(tab): + """处理 Turnstile 验证""" + print("准备处理验证") + try: + while True: + if tab.ele('@id=email-input', timeout=2): + print("无需验证 - 邮箱输入框已加载") + return True + + if tab.ele('@id=password', timeout=2): + print("无需验证 - 密码输入框已加载") + return True + + try: + challenge_element = (tab.ele("@name=cf-turnstile-response", timeout=2) + .parent() + .shadow_root + .ele("tag:iframe") + .ele("tag:body") + .sr("tag:input")) + + if challenge_element: + print("验证框加载完成") + time.sleep(random.uniform(1, 3)) + challenge_element.click() + print("验证按钮已点击,等待验证完成...") + time.sleep(2) + return True + except: + pass + + time.sleep(2) + + except Exception as e: + print(f"验证处理出错: {str(e)}") + print('跳过验证') + return False + +account = 'your_chatgpt_account' +password = 'your_chatgpt_password' + +co = ChromiumOptions() +co.add_extension("turnstilePatch") +# co.headless() +co.set_user_agent('Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.6723.92 Safari/537.36') +co.set_pref('credentials_enable_service', False) +co.set_argument('--hide-crash-restore-bubble') +co.auto_port() + +browser = Chromium(co) +tab = browser.latest_tab +tab.run_js("try { turnstile.reset() } catch(e) { }") + +print("\n步骤1: 开始访问网站...") + +tab.get('https://chatgpt.com') +print('等待页面加载...') + +print("\n步骤2: 开始登录...") +for _ in range(5): + try: + if tab.ele('xpath:/html/body/div[1]/div[1]/main/div[1]/div[1]/div/div[1]/div/div[3]/div/button[1]'): + signin_btn = tab.ele('xpath:/html/body/div[1]/div[1]/main/div[1]/div[1]/div/div[1]/div/div[3]/div/button[1]') + print("找到黑色登录按钮:", signin_btn.text) + break + if tab.ele('@data-testid=login-button'): + signin_btn = tab.ele('@data-testid=login-button') + print("找到蓝色登录按钮:", signin_btn.text) + break + if tab.ele("@name=cf-turnstile-response"): + print('加载页面时出现CF验证, IP 质量太差, 请更换 IP 重新尝试!') + browser.quit() + exit() + time.sleep(3) + except Exception as e: + print(f"处理登录按钮时出错: {str(e)}") + +for _ in range(5): + try: + if signin_btn: + signin_btn.click() + print("点击登录按钮") + break + except Exception as e: + print(f"处理登录按钮时出错: {str(e)}") + time.sleep(3) +else: + print("尝试点击登录按钮失败,程序退出") + exit() + +handle_turnstile(tab) + +print("\n步骤3: 输入邮箱...") +for _ in range(5): + try: + if tab.ele('@id=email-input'): + tab.actions.click('@id=email-input').type(account) + time.sleep(0.5) + tab.ele('@class=continue-btn').click() + print("输入邮箱并点击继续") + break + except Exception as e: + print(f"加载邮箱输入框时出错: {str(e)}") + time.sleep(3) +else: + print("尝试加载邮箱输入框失败,程序退出") + browser.quit() + exit() + +handle_turnstile(tab) + +print("\n步骤4: 输入密码...") +for _ in range(5): + try: + if tab.ele('@id=password'): + print("密码输入框加载完成") + tab.actions.click('@id=password').input(password) + time.sleep(2) + tab.ele('@type=submit').click('js') + # tab.actions.click('@type=submit') + print("输入密码并JS点击登录") + break + except Exception as e: + print(f"输入密码时出错: {str(e)}") + time.sleep(3) +else: + print("尝试加载密码输入框失败,程序退出") + browser.quit() + exit() + +for _ in range(5): + try: + if tab.ele('有什么可以帮忙的?'): + print('登录成功!') + break + if tab.ele('重新发送电子邮件'): + print('提示需要邮箱验证码,脚本终止,请手动获取') + exit() + except Exception as e: + print(f"登录可能遇到问题: {str(e)}") + time.sleep(3) +else: + print("登录失败,程序退出") + browser.quit() + exit() + +time.sleep(random.uniform(1,2)) +print('\n',"步骤5: 获取access_token...") +browser.new_tab('https://chatgpt.com/api/auth/session') +tab = browser.latest_tab +time.sleep(1) +response_json = tab.json +if response_json and 'accessToken' in response_json: + access_token = response_json['accessToken'] + print('\n',"请复制保存你的access_token:",'\n') + print(access_token) +else: + print("错误:未找到access token") + +# input("\n按Enter键关闭浏览器...") +browser.quit() + diff --git a/log.txt b/log.txt new file mode 100644 index 0000000..856427d --- /dev/null +++ b/log.txt @@ -0,0 +1,90 @@ +[2024/12/26 13:11:03.37] 开始执行脚? +[2024/12/26 13:17:58.13] 开始执行脚? +ʼִɾע +***ȷѾhttps://tempmail.plus/zhɹcursor˺ţ*** + +ʼɾ˻... +˺ +Continue +׼֤ +֤ +֤ťѵȴ֤... + +Sign in +׼֤ +֤ +֤ťѵȴ֤... +׼֤ +֤ +ҳ +Adavance +Delete Account +delete +Delete +˻ɾɹ + +ʼע˻... +Ѵעҳ + +עᰴť +׼֤ +֤ +֤ťѵȴ֤... + +Continueť +׼֤ +֤ +֤ťѵȴ֤... +ҳ +µʼ Cursor +07:19 +Verify your email address +֤룺 227917 +ɾʼ +ȡ֤ɹ 227917 +׼֤ +֤ +֤ťѵȴ֤... +ҳ +ע +Cursor ˺ţ apxeme@mailto.plus + 룺 ccz14321@ +CursorSessionToken: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJhdXRoMHx1c2VyXzAxSkcwUEZXQUNHSEQ5SDVNU1RWWlFHUDZOIiwidGltZSI6IjE3MzUxOTA0MDEiLCJyYW5kb21uZXNzIjoiYTM4NDBhYzEtZGYwNi00NDhkIiwiZXhwIjo0MzI3MTkwNDAxLCJpc3MiOiJodHRwczovL2F1dGhlbnRpY2F0aW9uLmN1cnNvci5zaCIsInNjb3BlIjoib3BlbmlkIHByb2ZpbGUgZW1haWwgb2ZmbGluZV9hY2Nlc3MiLCJhdWQiOiJodHRwczovL2N1cnNvci5jb20ifQ.YYQ_C4BjbkHlShTFElkOvXFDqA8kYA-aWMqHKLa5RsU +˻עɹ +ɹ cachedEmail +ɹ accessToken +ɹ refreshToken +űִ +[2024/12/26 13:20:14.57] 脚本执行完成 +Traceback (most recent call last): + File "cursor_pro_keep_alive.py", line 370, in + if delete_account(browser, tab): + ~~~~~~~~~~~~~~^^^^^^^^^^^^^^ + File "cursor_pro_keep_alive.py", line 146, in delete_account + if tab.ele("Account Settings"): + ~~~~~~~^^^^^^^^^^^^^^^^^^^^ + File "DrissionPage\_pages\mix_tab.py", line 109, in ele + File "DrissionPage\_pages\chromium_base.py", line 424, in ele + File "DrissionPage\_base\base.py", line 356, in _ele + File "DrissionPage\_pages\mix_tab.py", line 192, in _find_elements + File "DrissionPage\_pages\chromium_base.py", line 492, in _find_elements + File "DrissionPage\_base\driver.py", line 176, in run + File "DrissionPage\_base\driver.py", line 84, in _send + File "queue.py", line 213, in get + File "threading.py", line 363, in wait +KeyboardInterrupt +[PYI-35588:ERROR] Failed to execute script 'cursor_pro_keep_alive' due to unhandled exception! +ʼִɾע +***ȷѾhttps://tempmail.plus/zhɹcursor˺ţ*** + +ʼɾ˻... +˺ +Continue +׼֤ +֤ +֤ťѵȴ֤... + +Sign in +׼֤ +֤ +֤ťѵȴ֤... diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..84da24a --- /dev/null +++ b/requirements.txt @@ -0,0 +1,27 @@ +altgraph==0.17.4 +certifi==2024.12.14 +charset-normalizer==3.4.1 +click==8.1.8 +colorama==0.4.6 +cssselect==1.2.0 +DataRecorder==3.6.2 +DownloadKit==2.0.7 +DrissionPage==4.1.0.9 +et_xmlfile==2.0.0 +filelock==3.16.1 +idna==3.10 +lxml==5.3.0 +openpyxl==3.1.5 +packaging==24.2 +pefile==2023.2.7 +psutil==6.1.1 +pyinstaller==6.11.1 +pyinstaller-hooks-contrib==2024.11 +PyVirtualDisplay==3.0 +pywin32-ctypes==0.2.3 +requests==2.32.3 +requests-file==2.1.0 +setuptools==75.6.0 +tldextract==5.1.3 +urllib3==2.3.0 +websocket-client==1.8.0 diff --git a/run_cursor.bat b/run_cursor.bat new file mode 100644 index 0000000..db2df60 --- /dev/null +++ b/run_cursor.bat @@ -0,0 +1,11 @@ +@echo off +:: 设置控制台代码页为 UTF-8 +chcp 65001 +:: 设置 Python 环境变量为 UTF-8 +set PYTHONIOENCODING=utf-8 + +echo [%date% %time%] 开始执行脚本 >> log.txt +cd /d "%~dp0" +python cursor_pro_keep_alive.py >> log.txt 2>&1 +echo [%date% %time%] 脚本执行完成 >> log.txt +pause \ No newline at end of file diff --git a/turnstilePatch/manifest.json b/turnstilePatch/manifest.json new file mode 100644 index 0000000..3f4c606 --- /dev/null +++ b/turnstilePatch/manifest.json @@ -0,0 +1,18 @@ +{ + "manifest_version": 3, + "name": "Turnstile Patcher", + "version": "2.1", + "content_scripts": [ + { + "js": [ + "./script.js" + ], + "matches": [ + "" + ], + "run_at": "document_start", + "all_frames": true, + "world": "MAIN" + } + ] +} \ No newline at end of file diff --git a/turnstilePatch/readme.txt b/turnstilePatch/readme.txt new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/turnstilePatch/readme.txt @@ -0,0 +1 @@ + diff --git a/turnstilePatch/script.js b/turnstilePatch/script.js new file mode 100644 index 0000000..a46d798 --- /dev/null +++ b/turnstilePatch/script.js @@ -0,0 +1,12 @@ +function getRandomInt(min, max) { + return Math.floor(Math.random() * (max - min + 1)) + min; +} + +// old method wouldn't work on 4k screens + +let screenX = getRandomInt(800, 1200); +let screenY = getRandomInt(400, 600); + +Object.defineProperty(MouseEvent.prototype, 'screenX', { value: screenX }); + +Object.defineProperty(MouseEvent.prototype, 'screenY', { value: screenY }); \ No newline at end of file diff --git a/update_cursor_auth.py b/update_cursor_auth.py new file mode 100644 index 0000000..1a22459 --- /dev/null +++ b/update_cursor_auth.py @@ -0,0 +1,46 @@ +from cursor_auth_manager import CursorAuthManager + +def update_cursor_auth(email=None, access_token=None, refresh_token=None): + """ + 更新Cursor的认证信息的便捷函数 + """ + auth_manager = CursorAuthManager() + return auth_manager.update_auth(email, access_token, refresh_token) + +def main(): + # 示例用法 + print("请选择要更新的项目:") + print("1. 更新邮箱") + print("2. 更新访问令牌") + print("3. 更新刷新令牌") + print("4. 更新多个值") + print("0. 退出") + + choice = input("\n请输入选项数字: ") + + if choice == "1": + email = input("请输入新的邮箱: ") + update_cursor_auth(email=email) + elif choice == "2": + token = input("请输入新的访问令牌: ") + update_cursor_auth(access_token=token) + elif choice == "3": + token = input("请输入新的刷新令牌: ") + update_cursor_auth(refresh_token=token) + elif choice == "4": + email = input("请输入新的邮箱 (直接回车跳过): ") + access_token = input("请输入新的访问令牌 (直接回车跳过): ") + refresh_token = input("请输入新的刷新令牌 (直接回车跳过): ") + + update_cursor_auth( + email=email if email else None, + access_token=access_token if access_token else None, + refresh_token=refresh_token if refresh_token else None + ) + elif choice == "0": + print("退出程序") + else: + print("无效的选项") + +if __name__ == "__main__": + main() \ No newline at end of file