Sfoglia il codice sorgente

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.
chengchongzhen 1 anno fa
commit
d48b1a9d6d

+ 4 - 0
.gitignore

@@ -0,0 +1,4 @@
+.idea
+__pycache__
+
+build

+ 42 - 0
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,
+)

+ 5 - 0
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 

+ 5 - 0
config.ini

@@ -0,0 +1,5 @@
+[Account]
+email = apxeme@mailto.plus
+password = ccz14321@
+first_name = cheng
+last_name = zhen 

+ 60 - 0
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()

+ 453 - 0
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按回车键退出...")

+ 5 - 0
dist/config - 副本.ini

@@ -0,0 +1,5 @@
+[Account]
+email = xxxx
+password = xxx
+first_name = xxxx
+last_name = xxxx

+ 5 - 0
dist/config.ini

@@ -0,0 +1,5 @@
+[Account]
+email = apxeme@mailto.plus
+password = ccz14321@
+first_name = cheng
+last_name = zhen 

BIN
dist/cursor_pro_keep_alive.exe


+ 95 - 0
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. 免责声明
+
+本程序仅供学习和研究使用,请遵守相关服务条款和法律法规。使用本程序产生的任何后果由用户自行承担。

+ 166 - 0
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()
+  

+ 90 - 0
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 <no-reply@cursor.sh>
+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 <module>
+    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
+准备处理验证
+验证框加载完成
+验证按钮已点击,等待验证完成...

+ 27 - 0
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

+ 11 - 0
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

+ 18 - 0
turnstilePatch/manifest.json

@@ -0,0 +1,18 @@
+{
+    "manifest_version": 3,
+    "name": "Turnstile Patcher",
+    "version": "2.1",
+    "content_scripts": [
+        {
+            "js": [
+                "./script.js"
+            ],
+            "matches": [
+                "<all_urls>"
+            ],
+            "run_at": "document_start",
+            "all_frames": true,
+            "world": "MAIN"
+        }
+    ]
+}

+ 1 - 0
turnstilePatch/readme.txt

@@ -0,0 +1 @@
+

+ 12 - 0
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 });

+ 46 - 0
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()