mirror of
https://git.axenov.dev/mirrors/cursor-free-vip.git
synced 2026-01-02 17:01:03 +03:00
Compare commits
22 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
02851c9a09 | ||
|
|
6312d66813 | ||
|
|
1b1a21f3d7 | ||
|
|
c94bd605e5 | ||
|
|
9f6eee77e0 | ||
|
|
2bdcc2f633 | ||
|
|
4aabe2e403 | ||
|
|
005aa2cd95 | ||
|
|
14f6dfc29d | ||
|
|
2e9bd269ad | ||
|
|
f9b7e23253 | ||
|
|
0d979f7543 | ||
|
|
cce3025f7f | ||
|
|
fe3e27561b | ||
|
|
bf2bea71eb | ||
|
|
77a61647dd | ||
|
|
813dd4431e | ||
|
|
d7116b8cf3 | ||
|
|
f5a7acc4e3 | ||
|
|
479933844a | ||
|
|
93046d7f03 | ||
|
|
e7ca31b710 |
4
.github/workflows/build.yml
vendored
4
.github/workflows/build.yml
vendored
@@ -6,7 +6,7 @@ on:
|
|||||||
version:
|
version:
|
||||||
description: 'Version number (e.g. 1.0.9)'
|
description: 'Version number (e.g. 1.0.9)'
|
||||||
required: true
|
required: true
|
||||||
default: '1.4.01'
|
default: '1.5.03'
|
||||||
|
|
||||||
permissions:
|
permissions:
|
||||||
contents: write
|
contents: write
|
||||||
@@ -206,4 +206,4 @@ jobs:
|
|||||||
draft: false
|
draft: false
|
||||||
prerelease: false
|
prerelease: false
|
||||||
env:
|
env:
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
|||||||
4
.gitignore
vendored
4
.gitignore
vendored
@@ -13,6 +13,7 @@ build.mac.command
|
|||||||
build.py
|
build.py
|
||||||
build.sh
|
build.sh
|
||||||
ENV/
|
ENV/
|
||||||
|
test.py
|
||||||
|
|
||||||
install.bat
|
install.bat
|
||||||
run.bat
|
run.bat
|
||||||
@@ -45,3 +46,6 @@ Thumbs.db
|
|||||||
*.log
|
*.log
|
||||||
*.db
|
*.db
|
||||||
*.sqlite3
|
*.sqlite3
|
||||||
|
|
||||||
|
# Mac
|
||||||
|
run_venv.mac.command
|
||||||
38
CHANGELOG.md
38
CHANGELOG.md
@@ -1,5 +1,43 @@
|
|||||||
# Change Log
|
# Change Log
|
||||||
|
|
||||||
|
## v1.7.01
|
||||||
|
- Refactoring: Extract configuration-related code from the `setup_driver` function to an independent `setup_config` function
|
||||||
|
- Optimization: Improve code maintainability and make configuration management and browser settings more clear
|
||||||
|
- Improvement: The creation and update logic of the configuration file is clearer and more independent
|
||||||
|
|
||||||
|
## v1.6.03
|
||||||
|
1. Hotfix: Small Problem | 修復一些問題
|
||||||
|
|
||||||
|
## v1.6.02
|
||||||
|
1. Hotfix: Small Problem | 修復一些問題
|
||||||
|
2. Add: Test some Bypass Code | 測試一些繞過代碼
|
||||||
|
|
||||||
|
## v1.6.01
|
||||||
|
1. Fix: Cursor Auth | 修復Cursor Auth
|
||||||
|
2. Add: Create Account Maximum Retry | 增加創建賬號最大重試次數
|
||||||
|
3. Fix: Cursor Auth Error | 修復Cursor Auth錯誤
|
||||||
|
4. Fix: Update Curl Faild | 修復更新Curl失敗
|
||||||
|
|
||||||
|
## v1.5.03
|
||||||
|
1. HOTFIX: Stuck on starting browser | 修復啟動瀏覽器卡住問題
|
||||||
|
2. Small Fix: Error Handling | 小修錯誤處理
|
||||||
|
3. Small Fix: Translation | 小修翻譯
|
||||||
|
4. Small Fix: Performance | 小修性能
|
||||||
|
|
||||||
|
## v1.5.02
|
||||||
|
1. Add: Generate Random Name Alias | 增加生成隨機真實姓名
|
||||||
|
2. Add: Realistic Name Input | 增加真實姓名輸入
|
||||||
|
3. Optimize: Error Handling | 優化錯誤處理
|
||||||
|
4. Optimize: Translation | 優化翻譯
|
||||||
|
5. Optimize: Performance | 優化性能
|
||||||
|
|
||||||
|
## v1.5.01
|
||||||
|
1. Add: Check Latest Version | 增加檢查最新版本
|
||||||
|
2. Add: Update Command | 增加更新命令
|
||||||
|
|
||||||
|
## v1.4.08
|
||||||
|
1. Add: Print Some Account Info | 增加打印一些賬號信息
|
||||||
|
|
||||||
## v1.4.07
|
## v1.4.07
|
||||||
1. Add Removed break statements after each operation | 修改結束event後的break暫停應用
|
1. Add Removed break statements after each operation | 修改結束event後的break暫停應用
|
||||||
2. Added print_menu() calls to show the menu again | 添加print_menu()調用以再次顯示菜單
|
2. Added print_menu() calls to show the menu again | 添加print_menu()調用以再次顯示菜單
|
||||||
|
|||||||
30
README.md
30
README.md
@@ -1,7 +1,7 @@
|
|||||||
# ➤ Cursor Free VIP
|
# ➤ Cursor Free VIP
|
||||||
<div align="center">
|
<div align="center">
|
||||||
<p align="center">
|
<p align="center">
|
||||||
<img src="./images/logo.png" alt="Cursor Pro Logo" width="200"/>
|
<img src="./images/logo.png" alt="Cursor Pro Logo" width="200" style="border-radius: 6px;"/>
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<p align="center">
|
<p align="center">
|
||||||
@@ -12,14 +12,14 @@
|
|||||||
[](https://github.com/yeongpin/cursor-free-vip/releases/latest)
|
[](https://github.com/yeongpin/cursor-free-vip/releases/latest)
|
||||||
|
|
||||||
</p>
|
</p>
|
||||||
<h4>Support Latest 0.46.3 Version | 支持最新0.46.3本</h4>
|
<h4>Support Latest 0.46.8 Version | 支持最新0.46.8本</h4>
|
||||||
|
|
||||||
This is a tool to automatically register , support Windows and macOS systems, complete Auth verification, and reset Cursor's configuration.
|
This is a tool to automatically register , support Windows and macOS systems, complete Auth verification, and reset Cursor's configuration.
|
||||||
|
|
||||||
這是一個自動化工具,自動註冊 ,支持 Windows 和 macOS 系統,完成Auth驗證,重置Cursor的配置。
|
這是一個自動化工具,自動註冊 ,支持 Windows 和 macOS 系統,完成Auth驗證,重置Cursor的配置。
|
||||||
|
|
||||||
<p align="center">
|
<p align="center">
|
||||||
<img src="./images/pronew_2025-02-13_15-01-32.png" alt="new" width="400"/><br>
|
<img src="./images/new_2025-02-27_10-42-44.png" alt="new" width="400" style="border-radius: 6px;"/><br>
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
##### If you dont have google chrome , you can download it from [here](https://www.google.com/intl/en_pk/chrome/)
|
##### If you dont have google chrome , you can download it from [here](https://www.google.com/intl/en_pk/chrome/)
|
||||||
@@ -86,6 +86,21 @@ irm https://raw.githubusercontent.com/yeongpin/cursor-free-vip/main/scripts/rese
|
|||||||
|
|
||||||
## ❗ Note | 注意事項
|
## ❗ Note | 注意事項
|
||||||
|
|
||||||
|
📝 Config | 文件配置
|
||||||
|
`Win / Macos / Linux Path | 路徑 [Documents/.cursor-free-vip/config.ini]`
|
||||||
|
|
||||||
|
```
|
||||||
|
[Chrome]
|
||||||
|
# Default Google Chrome Path | 默認Google Chrome 遊覽器路徑
|
||||||
|
chromepath = C:\Program Files\Google/Chrome/Application/chrome.exe
|
||||||
|
|
||||||
|
[Turnstile]
|
||||||
|
# Handle Tuenstile Wait Time | 等待人機驗證時間
|
||||||
|
handle_turnstile_time = 2
|
||||||
|
# Handle Tuenstile Wait Random Time (must merge 1-3 or 1,3) | 等待人機驗證隨機時間(必須是 1-3 或者 1,3 這樣的組合)
|
||||||
|
handle_turnstile_random_time = 1-3
|
||||||
|
```
|
||||||
|
|
||||||
* Use administrator to run the script <br>請使用管理員身份運行腳本
|
* Use administrator to run the script <br>請使用管理員身份運行腳本
|
||||||
|
|
||||||
* Confirm that Cursor is closed before running the script <br>請確保在運行腳本前已經關閉 Cursor<br>
|
* Confirm that Cursor is closed before running the script <br>請確保在運行腳本前已經關閉 Cursor<br>
|
||||||
@@ -98,9 +113,9 @@ irm https://raw.githubusercontent.com/yeongpin/cursor-free-vip/main/scripts/rese
|
|||||||
|
|
||||||
## 🚨 Common Issues | 常見問題
|
## 🚨 Common Issues | 常見問題
|
||||||
|
|
||||||
|如果遇到權限問題,請確保:|If you encounter permission issues, please ensure:|
|
|如果遇到權限問題,請確保:| 此腳本以管理員身份運行 |
|
||||||
|:---:|:---:|
|
|:---:|:---:|
|
||||||
| 此腳本以管理員身份運行 | This script is run with administrator privileges |
|
|If you encounter permission issues, please ensure: | This script is run with administrator privileges |
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -109,6 +124,11 @@ irm https://raw.githubusercontent.com/yeongpin/cursor-free-vip/main/scripts/rese
|
|||||||
歡迎提交 Issue 和 Pull Request!
|
歡迎提交 Issue 和 Pull Request!
|
||||||
|
|
||||||
|
|
||||||
|
<a href="https://github.com/yeongpin/cursor-free-vip/graphs/contributors">
|
||||||
|
<img src="https://contrib.rocks/image?repo=yeongpin/cursor-free-vip" />
|
||||||
|
</a>
|
||||||
|
<br /><br />
|
||||||
|
|
||||||
|
|
||||||
## 📩 Disclaimer | 免責聲明
|
## 📩 Disclaimer | 免責聲明
|
||||||
|
|
||||||
|
|||||||
59
control.py
59
control.py
@@ -45,65 +45,6 @@ class BrowserControl:
|
|||||||
print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('control.create_new_tab_failed', error=str(e))}{Style.RESET_ALL}")
|
print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('control.create_new_tab_failed', error=str(e))}{Style.RESET_ALL}")
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def switch_to_tab(self, browser):
|
|
||||||
"""切换到指定浏览器窗口"""
|
|
||||||
try:
|
|
||||||
self.browser = browser
|
|
||||||
print(f"{Fore.GREEN}{EMOJI['SUCCESS']} {self.translator.get('control.switch_tab_success')}{Style.RESET_ALL}")
|
|
||||||
return True
|
|
||||||
except Exception as e:
|
|
||||||
print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('control.switch_tab_failed', error=str(e))}{Style.RESET_ALL}")
|
|
||||||
return False
|
|
||||||
|
|
||||||
def get_current_tab(self):
|
|
||||||
"""获取当前标签页"""
|
|
||||||
return self.browser
|
|
||||||
|
|
||||||
def wait_for_page_load(self, seconds=2):
|
|
||||||
"""等待页面加载"""
|
|
||||||
time.sleep(seconds)
|
|
||||||
|
|
||||||
def navigate_to(self, url):
|
|
||||||
"""导航到指定URL"""
|
|
||||||
try:
|
|
||||||
print(f"{Fore.CYAN}{EMOJI['INFO']} {self.translator.get('control.navigate_to', url=url)}...{Style.RESET_ALL}")
|
|
||||||
self.browser.get(url)
|
|
||||||
self.wait_for_page_load()
|
|
||||||
return True
|
|
||||||
except Exception as e:
|
|
||||||
print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('control.browser_error', error=str(e))}{Style.RESET_ALL}")
|
|
||||||
return False
|
|
||||||
|
|
||||||
def get_verification_code(self):
|
|
||||||
"""从邮件中获取验证码"""
|
|
||||||
try:
|
|
||||||
# 尝试所有可能的样式组合
|
|
||||||
selectors = [
|
|
||||||
# 新样式
|
|
||||||
'xpath://div[contains(@style, "font-family:-apple-system") and contains(@style, "font-size:28px") and contains(@style, "letter-spacing:2px") and contains(@style, "color:#202020")]',
|
|
||||||
# 带行高的样式
|
|
||||||
'xpath://div[contains(@style, "font-size:28px") and contains(@style, "letter-spacing:2px") and contains(@style, "line-height:30px")]',
|
|
||||||
# rgba 颜色样式
|
|
||||||
'xpath://div[contains(@style, "font-size: 28px") and contains(@style, "letter-spacing: 2px") and contains(@style, "color: rgba(32, 32, 32, 1)")]',
|
|
||||||
# 宽松样式
|
|
||||||
'xpath://div[contains(@style, "font-size:28px") and contains(@style, "letter-spacing:2px")]'
|
|
||||||
]
|
|
||||||
|
|
||||||
# 依次尝试每个选择器
|
|
||||||
for selector in selectors:
|
|
||||||
code_div = self.browser.ele(selector)
|
|
||||||
if code_div:
|
|
||||||
verification_code = code_div.text.strip()
|
|
||||||
if verification_code.isdigit() and len(verification_code) == 6:
|
|
||||||
print(f"{Fore.GREEN}{EMOJI['SUCCESS']} {self.translator.get('control.found_verification_code')}: {verification_code}{Style.RESET_ALL}")
|
|
||||||
return verification_code
|
|
||||||
|
|
||||||
print(f"{Fore.YELLOW}{EMOJI['ERROR']} {self.translator.get('control.no_valid_verification_code')}{Style.RESET_ALL}")
|
|
||||||
return None
|
|
||||||
|
|
||||||
except Exception as e:
|
|
||||||
print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('control.get_verification_code_error', error=str(e))}{Style.RESET_ALL}")
|
|
||||||
return None
|
|
||||||
|
|
||||||
def fill_verification_code(self, code):
|
def fill_verification_code(self, code):
|
||||||
"""填写验证码"""
|
"""填写验证码"""
|
||||||
|
|||||||
@@ -22,18 +22,21 @@ class CursorAuth:
|
|||||||
def __init__(self, translator=None):
|
def __init__(self, translator=None):
|
||||||
self.translator = translator
|
self.translator = translator
|
||||||
# 判断操作系统
|
# 判断操作系统
|
||||||
if os.name == "nt": # Windows
|
if sys.platform == "win32": # Windows
|
||||||
self.db_path = os.path.join(
|
self.db_path = os.path.join(
|
||||||
os.getenv("APPDATA"), "Cursor", "User", "globalStorage", "state.vscdb"
|
os.getenv("APPDATA"), "Cursor", "User", "globalStorage", "state.vscdb"
|
||||||
)
|
)
|
||||||
elif os.name =='posix':
|
elif sys.platform == 'linux':
|
||||||
self.db_path = os.path.expanduser(
|
self.db_path = os.path.expanduser(
|
||||||
"~/.config/Cursor/User/globalStorage/state.vscdb"
|
"~/.config/Cursor/User/globalStorage/state.vscdb"
|
||||||
)
|
)
|
||||||
else: # macOS
|
elif sys.platform == 'darwin': # macOS
|
||||||
self.db_path = os.path.expanduser(
|
self.db_path = os.path.expanduser(
|
||||||
"~/Library/Application Support/Cursor/User/globalStorage/state.vscdb"
|
"~/Library/Application Support/Cursor/User/globalStorage/state.vscdb"
|
||||||
)
|
)
|
||||||
|
else:
|
||||||
|
print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('auth.unsupported_platform')}{Style.RESET_ALL}")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
# 检查数据库文件是否存在
|
# 检查数据库文件是否存在
|
||||||
if not os.path.exists(self.db_path):
|
if not os.path.exists(self.db_path):
|
||||||
@@ -87,13 +90,16 @@ class CursorAuth:
|
|||||||
|
|
||||||
# 设置要更新的键值对
|
# 设置要更新的键值对
|
||||||
updates = []
|
updates = []
|
||||||
|
|
||||||
|
updates.append(("cursorAuth/cachedSignUpType", "Auth_0"))
|
||||||
|
|
||||||
if email is not None:
|
if email is not None:
|
||||||
updates.append(("cursorAuth/cachedEmail", email))
|
updates.append(("cursorAuth/cachedEmail", email))
|
||||||
if access_token is not None:
|
if access_token is not None:
|
||||||
updates.append(("cursorAuth/accessToken", access_token))
|
updates.append(("cursorAuth/accessToken", access_token))
|
||||||
if refresh_token is not None:
|
if refresh_token is not None:
|
||||||
updates.append(("cursorAuth/refreshToken", refresh_token))
|
updates.append(("cursorAuth/refreshToken", refresh_token))
|
||||||
updates.append(("cursorAuth/cachedSignUpType", "Auth_0"))
|
|
||||||
|
|
||||||
# 使用事务来确保数据完整性
|
# 使用事务来确保数据完整性
|
||||||
cursor.execute("BEGIN TRANSACTION")
|
cursor.execute("BEGIN TRANSACTION")
|
||||||
@@ -131,5 +137,3 @@ class CursorAuth:
|
|||||||
if conn:
|
if conn:
|
||||||
conn.close()
|
conn.close()
|
||||||
print(f"{EMOJI['DB']} {Fore.CYAN} {self.translator.get('auth.database_connection_closed')}{Style.RESET_ALL}")
|
print(f"{EMOJI['DB']} {Fore.CYAN} {self.translator.get('auth.database_connection_closed')}{Style.RESET_ALL}")
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -10,10 +10,10 @@ from reset_machine_manual import MachineIDResetter
|
|||||||
os.environ["PYTHONVERBOSE"] = "0"
|
os.environ["PYTHONVERBOSE"] = "0"
|
||||||
os.environ["PYINSTALLER_VERBOSE"] = "0"
|
os.environ["PYINSTALLER_VERBOSE"] = "0"
|
||||||
|
|
||||||
# 初始化colorama
|
# Initialize colorama
|
||||||
init()
|
init()
|
||||||
|
|
||||||
# 定义emoji常量
|
# Define emoji constants
|
||||||
EMOJI = {
|
EMOJI = {
|
||||||
'START': '🚀',
|
'START': '🚀',
|
||||||
'FORM': '📝',
|
'FORM': '📝',
|
||||||
@@ -33,7 +33,7 @@ EMOJI = {
|
|||||||
class CursorRegistration:
|
class CursorRegistration:
|
||||||
def __init__(self, translator=None):
|
def __init__(self, translator=None):
|
||||||
self.translator = translator
|
self.translator = translator
|
||||||
# 设置为显示模式
|
# Set to display mode
|
||||||
os.environ['BROWSER_HEADLESS'] = 'False'
|
os.environ['BROWSER_HEADLESS'] = 'False'
|
||||||
self.browser_manager = BrowserManager()
|
self.browser_manager = BrowserManager()
|
||||||
self.browser = None
|
self.browser = None
|
||||||
@@ -47,38 +47,49 @@ class CursorRegistration:
|
|||||||
|
|
||||||
# 账号信息
|
# 账号信息
|
||||||
self.password = self._generate_password()
|
self.password = self._generate_password()
|
||||||
self.first_name = self._generate_name()
|
# Generate first name and last name separately
|
||||||
self.last_name = self._generate_name()
|
first_name = random.choice([
|
||||||
|
"James", "John", "Robert", "Michael", "William", "David", "Joseph", "Thomas",
|
||||||
|
"Emma", "Olivia", "Ava", "Isabella", "Sophia", "Mia", "Charlotte", "Amelia",
|
||||||
|
"Liam", "Noah", "Oliver", "Elijah", "Lucas", "Mason", "Logan", "Alexander"
|
||||||
|
])
|
||||||
|
self.last_name = random.choice([
|
||||||
|
"Smith", "Johnson", "Williams", "Brown", "Jones", "Garcia", "Miller", "Davis",
|
||||||
|
"Anderson", "Wilson", "Taylor", "Thomas", "Moore", "Martin", "Jackson", "Lee",
|
||||||
|
"Thompson", "White", "Harris", "Clark", "Lewis", "Walker", "Hall", "Young"
|
||||||
|
])
|
||||||
|
|
||||||
|
# Modify first letter of first name
|
||||||
|
new_first_letter = random.choice("ABCDEFGHIJKLMNOPQRSTUVWXYZ")
|
||||||
|
self.first_name = new_first_letter + first_name[1:]
|
||||||
|
|
||||||
|
print(f"\n{Fore.CYAN}{EMOJI['PASSWORD']} {self.translator.get('register.password')}: {self.password} {Style.RESET_ALL}")
|
||||||
|
print(f"{Fore.CYAN}{EMOJI['FORM']} {self.translator.get('register.first_name')}: {self.first_name} {Style.RESET_ALL}")
|
||||||
|
print(f"{Fore.CYAN}{EMOJI['FORM']} {self.translator.get('register.last_name')}: {self.last_name} {Style.RESET_ALL}")
|
||||||
|
|
||||||
def _generate_password(self, length=12):
|
def _generate_password(self, length=12):
|
||||||
"""Generate Random Password"""
|
"""Generate Random Password"""
|
||||||
chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!@#$%^&*"
|
chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!@#$%^&*"
|
||||||
return ''.join(random.choices(chars, k=length))
|
return ''.join(random.choices(chars, k=length))
|
||||||
|
|
||||||
def _generate_name(self, length=6):
|
|
||||||
"""Generate Random Name"""
|
|
||||||
first_letter = random.choice("ABCDEFGHIJKLMNOPQRSTUVWXYZ")
|
|
||||||
rest_letters = ''.join(random.choices("abcdefghijklmnopqrstuvwxyz", k=length-1))
|
|
||||||
return first_letter + rest_letters
|
|
||||||
|
|
||||||
def setup_email(self):
|
def setup_email(self):
|
||||||
"""设置邮箱"""
|
"""Setup Email"""
|
||||||
try:
|
try:
|
||||||
print(f"{Fore.CYAN}{EMOJI['START']} {self.translator.get('register.browser_start')}...{Style.RESET_ALL}")
|
print(f"{Fore.CYAN}{EMOJI['START']} {self.translator.get('register.browser_start')}...{Style.RESET_ALL}")
|
||||||
|
|
||||||
# 使用 new_tempemail 创建临时邮箱,传入 translator
|
# Create a temporary email using new_tempemail, passing translator
|
||||||
from new_tempemail import NewTempEmail
|
from new_tempemail import NewTempEmail
|
||||||
self.temp_email = NewTempEmail(self.translator) # 传入 translator
|
self.temp_email = NewTempEmail(self.translator) # Pass translator
|
||||||
|
|
||||||
# 创建临时邮箱
|
# Create a temporary email
|
||||||
email_address = self.temp_email.create_email()
|
email_address = self.temp_email.create_email()
|
||||||
if not email_address:
|
if not email_address:
|
||||||
print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('register.email_create_failed')}{Style.RESET_ALL}")
|
print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('register.email_create_failed')}{Style.RESET_ALL}")
|
||||||
return False
|
return False
|
||||||
|
|
||||||
# 保存邮箱地址
|
# Save email address
|
||||||
self.email_address = email_address
|
self.email_address = email_address
|
||||||
self.email_tab = self.temp_email # 传递 NewTempEmail 实例
|
self.email_tab = self.temp_email # Pass NewTempEmail instance
|
||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
@@ -92,10 +103,10 @@ class CursorRegistration:
|
|||||||
try:
|
try:
|
||||||
print(f"{Fore.CYAN}{EMOJI['START']} {self.translator.get('register.register_start')}...{Style.RESET_ALL}")
|
print(f"{Fore.CYAN}{EMOJI['START']} {self.translator.get('register.register_start')}...{Style.RESET_ALL}")
|
||||||
|
|
||||||
# 直接使用 new_signup.py 进行注册
|
# Directly use new_signup.py to sign up
|
||||||
from new_signup import main as new_signup_main
|
from new_signup import main as new_signup_main
|
||||||
|
|
||||||
# 执行新的注册流程,传入 translator
|
# Execute the new registration process, passing translator
|
||||||
result, browser_tab = new_signup_main(
|
result, browser_tab = new_signup_main(
|
||||||
email=self.email_address,
|
email=self.email_address,
|
||||||
password=self.password,
|
password=self.password,
|
||||||
@@ -107,11 +118,11 @@ class CursorRegistration:
|
|||||||
)
|
)
|
||||||
|
|
||||||
if result:
|
if result:
|
||||||
# 使用返回的浏览器实例获取账户信息
|
# Use the returned browser instance to get account information
|
||||||
self.signup_tab = browser_tab # 保存浏览器实例
|
self.signup_tab = browser_tab # Save browser instance
|
||||||
success = self._get_account_info()
|
success = self._get_account_info()
|
||||||
|
|
||||||
# 获取信息后关闭浏览器
|
# Close browser after getting information
|
||||||
if browser_tab:
|
if browser_tab:
|
||||||
try:
|
try:
|
||||||
browser_tab.quit()
|
browser_tab.quit()
|
||||||
@@ -126,7 +137,7 @@ class CursorRegistration:
|
|||||||
print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('register.register_process_error', error=str(e))}{Style.RESET_ALL}")
|
print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('register.register_process_error', error=str(e))}{Style.RESET_ALL}")
|
||||||
return False
|
return False
|
||||||
finally:
|
finally:
|
||||||
# 确保在任何情况下都关闭浏览器
|
# Ensure browser is closed in any case
|
||||||
if browser_tab:
|
if browser_tab:
|
||||||
try:
|
try:
|
||||||
browser_tab.quit()
|
browser_tab.quit()
|
||||||
@@ -134,7 +145,7 @@ class CursorRegistration:
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
def _get_account_info(self):
|
def _get_account_info(self):
|
||||||
"""获取账户信息和 Token"""
|
"""Get Account Information and Token"""
|
||||||
try:
|
try:
|
||||||
self.signup_tab.get(self.settings_url)
|
self.signup_tab.get(self.settings_url)
|
||||||
time.sleep(2)
|
time.sleep(2)
|
||||||
@@ -149,6 +160,7 @@ class CursorRegistration:
|
|||||||
if usage_ele:
|
if usage_ele:
|
||||||
total_usage = usage_ele.text.split("/")[-1].strip()
|
total_usage = usage_ele.text.split("/")[-1].strip()
|
||||||
|
|
||||||
|
print(f"Total Usage: {total_usage}\n")
|
||||||
print(f"{Fore.CYAN}{EMOJI['WAIT']} {self.translator.get('register.get_token')}...{Style.RESET_ALL}")
|
print(f"{Fore.CYAN}{EMOJI['WAIT']} {self.translator.get('register.get_token')}...{Style.RESET_ALL}")
|
||||||
max_attempts = 30
|
max_attempts = 30
|
||||||
retry_interval = 2
|
retry_interval = 2
|
||||||
@@ -185,7 +197,7 @@ class CursorRegistration:
|
|||||||
return False
|
return False
|
||||||
|
|
||||||
def _save_account_info(self, token, total_usage):
|
def _save_account_info(self, token, total_usage):
|
||||||
"""保存账户信息到文件"""
|
"""Save Account Information to File"""
|
||||||
try:
|
try:
|
||||||
# 先更新认证信息
|
# 先更新认证信息
|
||||||
print(f"{Fore.CYAN}{EMOJI['KEY']} {self.translator.get('register.update_cursor_auth_info')}...{Style.RESET_ALL}")
|
print(f"{Fore.CYAN}{EMOJI['KEY']} {self.translator.get('register.update_cursor_auth_info')}...{Style.RESET_ALL}")
|
||||||
@@ -200,7 +212,7 @@ class CursorRegistration:
|
|||||||
if not resetter.reset_machine_ids(): # 直接调用reset_machine_ids方法
|
if not resetter.reset_machine_ids(): # 直接调用reset_machine_ids方法
|
||||||
raise Exception("Failed to reset machine ID")
|
raise Exception("Failed to reset machine ID")
|
||||||
|
|
||||||
# 保存账户信息到文件
|
# Save account information to file
|
||||||
with open('cursor_accounts.txt', 'a', encoding='utf-8') as f:
|
with open('cursor_accounts.txt', 'a', encoding='utf-8') as f:
|
||||||
f.write(f"\n{'='*50}\n")
|
f.write(f"\n{'='*50}\n")
|
||||||
f.write(f"Email: {self.email_address}\n")
|
f.write(f"Email: {self.email_address}\n")
|
||||||
@@ -217,7 +229,7 @@ class CursorRegistration:
|
|||||||
return False
|
return False
|
||||||
|
|
||||||
def start(self):
|
def start(self):
|
||||||
"""启动注册流程"""
|
"""Start Registration Process"""
|
||||||
try:
|
try:
|
||||||
if self.setup_email():
|
if self.setup_email():
|
||||||
if self.register_cursor():
|
if self.register_cursor():
|
||||||
@@ -225,7 +237,7 @@ class CursorRegistration:
|
|||||||
return True
|
return True
|
||||||
return False
|
return False
|
||||||
finally:
|
finally:
|
||||||
# 关闭邮箱标签页
|
# Close email tab
|
||||||
if hasattr(self, 'temp_email'):
|
if hasattr(self, 'temp_email'):
|
||||||
try:
|
try:
|
||||||
self.temp_email.close()
|
self.temp_email.close()
|
||||||
@@ -233,7 +245,7 @@ class CursorRegistration:
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
def update_cursor_auth(self, email=None, access_token=None, refresh_token=None):
|
def update_cursor_auth(self, email=None, access_token=None, refresh_token=None):
|
||||||
"""更新Cursor的认证信息的便捷函数"""
|
"""Update Cursor Auth Info"""
|
||||||
auth_manager = CursorAuth(translator=self.translator)
|
auth_manager = CursorAuth(translator=self.translator)
|
||||||
return auth_manager.update_auth(email, access_token, refresh_token)
|
return auth_manager.update_auth(email, access_token, refresh_token)
|
||||||
|
|
||||||
|
|||||||
@@ -44,22 +44,33 @@ class CursorRegistration:
|
|||||||
self.signup_tab = None
|
self.signup_tab = None
|
||||||
self.email_tab = None
|
self.email_tab = None
|
||||||
|
|
||||||
# Account information
|
# Generate account information
|
||||||
self.password = self._generate_password()
|
self.password = self._generate_password()
|
||||||
self.first_name = self._generate_name()
|
# Generate first name and last name separately
|
||||||
self.last_name = self._generate_name()
|
first_name = random.choice([
|
||||||
|
"James", "John", "Robert", "Michael", "William", "David", "Joseph", "Thomas",
|
||||||
|
"Emma", "Olivia", "Ava", "Isabella", "Sophia", "Mia", "Charlotte", "Amelia",
|
||||||
|
"Liam", "Noah", "Oliver", "Elijah", "Lucas", "Mason", "Logan", "Alexander"
|
||||||
|
])
|
||||||
|
self.last_name = random.choice([
|
||||||
|
"Smith", "Johnson", "Williams", "Brown", "Jones", "Garcia", "Miller", "Davis",
|
||||||
|
"Anderson", "Wilson", "Taylor", "Thomas", "Moore", "Martin", "Jackson", "Lee",
|
||||||
|
"Thompson", "White", "Harris", "Clark", "Lewis", "Walker", "Hall", "Young"
|
||||||
|
])
|
||||||
|
|
||||||
|
# Modify first letter of first name
|
||||||
|
new_first_letter = random.choice("ABCDEFGHIJKLMNOPQRSTUVWXYZ")
|
||||||
|
self.first_name = new_first_letter + first_name[1:]
|
||||||
|
|
||||||
|
print(f"\n{Fore.CYAN}{EMOJI['PASSWORD']} {self.translator.get('register.password')}: {self.password} {Style.RESET_ALL}")
|
||||||
|
print(f"{Fore.CYAN}{EMOJI['FORM']} {self.translator.get('register.first_name')}: {self.first_name} {Style.RESET_ALL}")
|
||||||
|
print(f"{Fore.CYAN}{EMOJI['FORM']} {self.translator.get('register.last_name')}: {self.last_name} {Style.RESET_ALL}")
|
||||||
|
|
||||||
def _generate_password(self, length=12):
|
def _generate_password(self, length=12):
|
||||||
"""Generate Random Password"""
|
"""Generate Random Password"""
|
||||||
chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!@#$%^&*"
|
chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!@#$%^&*"
|
||||||
return ''.join(random.choices(chars, k=length))
|
return ''.join(random.choices(chars, k=length))
|
||||||
|
|
||||||
def _generate_name(self, length=6):
|
|
||||||
"""Generate Random Name"""
|
|
||||||
first_letter = random.choice("ABCDEFGHIJKLMNOPQRSTUVWXYZ")
|
|
||||||
rest_letters = ''.join(random.choices("abcdefghijklmnopqrstuvwxyz", k=length-1))
|
|
||||||
return first_letter + rest_letters
|
|
||||||
|
|
||||||
def setup_email(self):
|
def setup_email(self):
|
||||||
"""Setup Email"""
|
"""Setup Email"""
|
||||||
try:
|
try:
|
||||||
@@ -70,6 +81,7 @@ class CursorRegistration:
|
|||||||
print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('register.invalid_email') if self.translator else '无效的邮箱地址'}{Style.RESET_ALL}")
|
print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('register.invalid_email') if self.translator else '无效的邮箱地址'}{Style.RESET_ALL}")
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
print(f"{Fore.CYAN}{EMOJI['MAIL']} {self.translator.get('register.email_address')}: {self.email_address}\n{Style.RESET_ALL}")
|
||||||
return True
|
return True
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
@@ -155,6 +167,7 @@ class CursorRegistration:
|
|||||||
if usage_ele:
|
if usage_ele:
|
||||||
total_usage = usage_ele.text.split("/")[-1].strip()
|
total_usage = usage_ele.text.split("/")[-1].strip()
|
||||||
|
|
||||||
|
print(f"Total Usage: {total_usage}\n")
|
||||||
print(f"{Fore.CYAN}{EMOJI['WAIT']} {self.translator.get('register.get_token')}...{Style.RESET_ALL}")
|
print(f"{Fore.CYAN}{EMOJI['WAIT']} {self.translator.get('register.get_token')}...{Style.RESET_ALL}")
|
||||||
max_attempts = 30
|
max_attempts = 30
|
||||||
retry_interval = 2
|
retry_interval = 2
|
||||||
|
|||||||
BIN
images/new_2025-02-27_10-42-44.png
Normal file
BIN
images/new_2025-02-27_10-42-44.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 116 KiB |
@@ -131,7 +131,17 @@
|
|||||||
"register_process_error": "Register Process Error: {error}",
|
"register_process_error": "Register Process Error: {error}",
|
||||||
"setting_password": "Setting Password",
|
"setting_password": "Setting Password",
|
||||||
"manual_code_input": "Manual Code Input",
|
"manual_code_input": "Manual Code Input",
|
||||||
"manual_email_input": "Manual Email Input"
|
"manual_email_input": "Manual Email Input",
|
||||||
|
"password": "Password",
|
||||||
|
"first_name": "First Name",
|
||||||
|
"last_name": "Last Name",
|
||||||
|
"exit_signal": "Exit Signal",
|
||||||
|
"email_address": "Email Address",
|
||||||
|
"config_created": "Config Created",
|
||||||
|
"verification_failed": "Verification Failed",
|
||||||
|
"verification_error": "Verification Error: {error}",
|
||||||
|
"config_option_added": "Config Option Added: {option}",
|
||||||
|
"config_updated": "Config Updated"
|
||||||
},
|
},
|
||||||
"auth": {
|
"auth": {
|
||||||
"title": "Cursor Auth Manager",
|
"title": "Cursor Auth Manager",
|
||||||
@@ -219,7 +229,8 @@
|
|||||||
"blocked_domains_loaded_timeout": "Blocked Domains Loaded Timeout: {timeout}s",
|
"blocked_domains_loaded_timeout": "Blocked Domains Loaded Timeout: {timeout}s",
|
||||||
"blocked_domains_loaded_timeout_error": "Blocked Domains Loaded Timeout Error: {error}",
|
"blocked_domains_loaded_timeout_error": "Blocked Domains Loaded Timeout Error: {error}",
|
||||||
"available_domains_loaded": "Available Domains Loaded: {count}",
|
"available_domains_loaded": "Available Domains Loaded: {count}",
|
||||||
"domains_filtered": "Domains Filtered: {count}"
|
"domains_filtered": "Domains Filtered: {count}",
|
||||||
|
"trying_to_create_email": "Trying to create email: {email}"
|
||||||
},
|
},
|
||||||
"update": {
|
"update": {
|
||||||
"title": "Disable Cursor Auto Update",
|
"title": "Disable Cursor Auto Update",
|
||||||
@@ -233,5 +244,13 @@
|
|||||||
"directory_removed": "Directory Removed",
|
"directory_removed": "Directory Removed",
|
||||||
"creating_block_file": "Creating Block File",
|
"creating_block_file": "Creating Block File",
|
||||||
"block_file_created": "Block File Created"
|
"block_file_created": "Block File Created"
|
||||||
|
},
|
||||||
|
"updater": {
|
||||||
|
"checking": "Checking for updates...",
|
||||||
|
"new_version_available": "New version available! (Current: {current}, Latest: {latest})",
|
||||||
|
"updating": "Updating to the latest version. The program will restart automatically.",
|
||||||
|
"up_to_date": "You are using the latest version.",
|
||||||
|
"check_failed": "Failed to check for updates: {error}",
|
||||||
|
"continue_anyway": "Continuing with current version..."
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -131,7 +131,17 @@
|
|||||||
"update_cursor_auth_info": "更新Cursor认证信息",
|
"update_cursor_auth_info": "更新Cursor认证信息",
|
||||||
"setting_password": "设置密码",
|
"setting_password": "设置密码",
|
||||||
"manual_code_input": "手动输入验证码",
|
"manual_code_input": "手动输入验证码",
|
||||||
"manual_email_input": "手动输入邮箱"
|
"manual_email_input": "手动输入邮箱",
|
||||||
|
"password": "密码",
|
||||||
|
"first_name": "名字",
|
||||||
|
"last_name": "姓氏",
|
||||||
|
"exit_signal": "退出信号",
|
||||||
|
"email_address": "邮箱地址",
|
||||||
|
"config_created": "配置已创建",
|
||||||
|
"verification_failed": "验证失败",
|
||||||
|
"verification_error": "验证错误: {error}",
|
||||||
|
"config_option_added": "配置项已添加: {option}",
|
||||||
|
"config_updated": "配置已更新"
|
||||||
},
|
},
|
||||||
"auth": {
|
"auth": {
|
||||||
"title": "Cursor 认证管理器",
|
"title": "Cursor 认证管理器",
|
||||||
@@ -216,7 +226,8 @@
|
|||||||
"blocked_domains_loaded_timeout": "加载被屏蔽的域名超时: {timeout}秒",
|
"blocked_domains_loaded_timeout": "加载被屏蔽的域名超时: {timeout}秒",
|
||||||
"blocked_domains_loaded_timeout_error": "加载被屏蔽的域名超时错误: {error}",
|
"blocked_domains_loaded_timeout_error": "加载被屏蔽的域名超时错误: {error}",
|
||||||
"available_domains_loaded": "获取到 {count} 个可用域名",
|
"available_domains_loaded": "获取到 {count} 个可用域名",
|
||||||
"domains_filtered": "过滤后剩餘 {count} 個可用域名"
|
"domains_filtered": "过滤后剩餘 {count} 個可用域名",
|
||||||
|
"trying_to_create_email": "尝试创建邮箱: {email}"
|
||||||
},
|
},
|
||||||
"update": {
|
"update": {
|
||||||
"title": "禁用 Cursor 自动更新",
|
"title": "禁用 Cursor 自动更新",
|
||||||
@@ -230,5 +241,13 @@
|
|||||||
"directory_removed": "目录已删除",
|
"directory_removed": "目录已删除",
|
||||||
"creating_block_file": "创建阻止文件",
|
"creating_block_file": "创建阻止文件",
|
||||||
"block_file_created": "阻止文件已创建"
|
"block_file_created": "阻止文件已创建"
|
||||||
|
},
|
||||||
|
"updater": {
|
||||||
|
"checking": "检查更新...",
|
||||||
|
"new_version_available": "有新版本可用! (当前版本: {current}, 最新版本: {latest})",
|
||||||
|
"updating": "正在更新到最新版本。程序将自动重启。",
|
||||||
|
"up_to_date": "您使用的是最新版本。",
|
||||||
|
"check_failed": "检查更新失败: {error}",
|
||||||
|
"continue_anyway": "继续使用当前版本..."
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -112,7 +112,17 @@
|
|||||||
"update_cursor_auth_info": "更新Cursor認證信息",
|
"update_cursor_auth_info": "更新Cursor認證信息",
|
||||||
"setting_password": "設置密碼",
|
"setting_password": "設置密碼",
|
||||||
"manual_code_input": "手動輸入驗證碼",
|
"manual_code_input": "手動輸入驗證碼",
|
||||||
"manual_email_input": "手動輸入郵箱地址"
|
"manual_email_input": "手動輸入郵箱地址",
|
||||||
|
"password": "密碼",
|
||||||
|
"first_name": "名字",
|
||||||
|
"last_name": "姓氏",
|
||||||
|
"exit_signal": "退出信號",
|
||||||
|
"email_address": "郵箱地址",
|
||||||
|
"config_created": "配置已創建",
|
||||||
|
"verification_failed": "驗證失敗",
|
||||||
|
"verification_error": "驗證錯誤: {error}",
|
||||||
|
"config_option_added": "配置項已添加: {option}",
|
||||||
|
"config_updated": "配置已更新"
|
||||||
},
|
},
|
||||||
"auth": {
|
"auth": {
|
||||||
"title": "Cursor 認證管理器",
|
"title": "Cursor 認證管理器",
|
||||||
@@ -197,7 +207,8 @@
|
|||||||
"blocked_domains_loaded_timeout": "加載被屏蔽的域名超時: {timeout}秒",
|
"blocked_domains_loaded_timeout": "加載被屏蔽的域名超時: {timeout}秒",
|
||||||
"blocked_domains_loaded_timeout_error": "加載被屏蔽的域名超時錯誤: {error}",
|
"blocked_domains_loaded_timeout_error": "加載被屏蔽的域名超時錯誤: {error}",
|
||||||
"available_domains_loaded": "獲取到 {count} 個可用域名",
|
"available_domains_loaded": "獲取到 {count} 個可用域名",
|
||||||
"domains_filtered": "過濾後剩餘 {count} 個可用域名"
|
"domains_filtered": "過濾後剩餘 {count} 個可用域名",
|
||||||
|
"trying_to_create_email": "嘗試創建郵箱: {email}"
|
||||||
},
|
},
|
||||||
"update": {
|
"update": {
|
||||||
"title": "禁用 Cursor 自动更新",
|
"title": "禁用 Cursor 自动更新",
|
||||||
@@ -211,5 +222,13 @@
|
|||||||
"directory_removed": "目錄已刪除",
|
"directory_removed": "目錄已刪除",
|
||||||
"creating_block_file": "創建阻止文件",
|
"creating_block_file": "創建阻止文件",
|
||||||
"block_file_created": "阻止文件已創建"
|
"block_file_created": "阻止文件已創建"
|
||||||
|
},
|
||||||
|
"updater": {
|
||||||
|
"checking": "檢查更新...",
|
||||||
|
"new_version_available": "有新版本可用! (當前版本: {current}, 最新版本: {latest})",
|
||||||
|
"updating": "正在更新到最新版本。程序將自動重啟。",
|
||||||
|
"up_to_date": "您使用的是最新版本。",
|
||||||
|
"check_failed": "檢查更新失敗: {error}",
|
||||||
|
"continue_anyway": "繼續使用當前版本..."
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
83
main.py
83
main.py
@@ -3,10 +3,12 @@
|
|||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
import json
|
import json
|
||||||
from logo import print_logo
|
from logo import print_logo, version
|
||||||
from colorama import Fore, Style, init
|
from colorama import Fore, Style, init
|
||||||
import locale
|
import locale
|
||||||
import platform
|
import platform
|
||||||
|
import requests
|
||||||
|
import subprocess
|
||||||
|
|
||||||
# 只在 Windows 系统上导入 windll
|
# 只在 Windows 系统上导入 windll
|
||||||
if platform.system() == 'Windows':
|
if platform.system() == 'Windows':
|
||||||
@@ -203,8 +205,87 @@ def select_language():
|
|||||||
print(f"{Fore.RED}{EMOJI['ERROR']} {translator.get('menu.invalid_choice')}{Style.RESET_ALL}")
|
print(f"{Fore.RED}{EMOJI['ERROR']} {translator.get('menu.invalid_choice')}{Style.RESET_ALL}")
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
def check_latest_version():
|
||||||
|
"""Check if current version matches the latest release version"""
|
||||||
|
try:
|
||||||
|
print(f"\n{Fore.CYAN}{EMOJI['UPDATE']} {translator.get('updater.checking')}{Style.RESET_ALL}")
|
||||||
|
|
||||||
|
# Get latest version from GitHub API with timeout and proper headers
|
||||||
|
headers = {
|
||||||
|
'Accept': 'application/vnd.github.v3+json',
|
||||||
|
'User-Agent': 'CursorFreeVIP-Updater'
|
||||||
|
}
|
||||||
|
response = requests.get(
|
||||||
|
"https://api.github.com/repos/yeongpin/cursor-free-vip/releases/latest",
|
||||||
|
headers=headers,
|
||||||
|
timeout=10
|
||||||
|
)
|
||||||
|
|
||||||
|
# Check if response is successful
|
||||||
|
if response.status_code != 200:
|
||||||
|
raise Exception(f"GitHub API returned status code {response.status_code}")
|
||||||
|
|
||||||
|
response_data = response.json()
|
||||||
|
if "tag_name" not in response_data:
|
||||||
|
raise Exception("No version tag found in GitHub response")
|
||||||
|
|
||||||
|
latest_version = response_data["tag_name"].lstrip('v')
|
||||||
|
|
||||||
|
# Validate version format
|
||||||
|
if not latest_version:
|
||||||
|
raise Exception("Invalid version format received")
|
||||||
|
|
||||||
|
if latest_version != version:
|
||||||
|
print(f"\n{Fore.YELLOW}{EMOJI['INFO']} {translator.get('updater.new_version_available', current=version, latest=latest_version)}{Style.RESET_ALL}")
|
||||||
|
|
||||||
|
try:
|
||||||
|
# Execute update command based on platform
|
||||||
|
if platform.system() == 'Windows':
|
||||||
|
update_command = 'irm https://raw.githubusercontent.com/yeongpin/cursor-free-vip/main/scripts/install.ps1 | iex'
|
||||||
|
subprocess.run(['powershell', '-NoProfile', '-ExecutionPolicy', 'Bypass', '-Command', update_command], check=True)
|
||||||
|
else:
|
||||||
|
# For Linux/Mac, download and execute the install script
|
||||||
|
install_script_url = 'https://raw.githubusercontent.com/yeongpin/cursor-free-vip/main/scripts/install.sh'
|
||||||
|
|
||||||
|
# First verify the script exists
|
||||||
|
script_response = requests.get(install_script_url, timeout=5)
|
||||||
|
if script_response.status_code != 200:
|
||||||
|
raise Exception("Installation script not found")
|
||||||
|
|
||||||
|
# Save and execute the script
|
||||||
|
with open('install.sh', 'wb') as f:
|
||||||
|
f.write(script_response.content)
|
||||||
|
|
||||||
|
os.chmod('install.sh', 0o755) # Make executable
|
||||||
|
subprocess.run(['./install.sh'], check=True)
|
||||||
|
|
||||||
|
# Clean up
|
||||||
|
if os.path.exists('install.sh'):
|
||||||
|
os.remove('install.sh')
|
||||||
|
|
||||||
|
print(f"\n{Fore.GREEN}{EMOJI['SUCCESS']} {translator.get('updater.updating')}{Style.RESET_ALL}")
|
||||||
|
sys.exit(0)
|
||||||
|
|
||||||
|
except Exception as update_error:
|
||||||
|
print(f"{Fore.RED}{EMOJI['ERROR']} {translator.get('updater.update_failed', error=str(update_error))}{Style.RESET_ALL}")
|
||||||
|
print(f"{Fore.YELLOW}{EMOJI['INFO']} {translator.get('updater.manual_update_required')}{Style.RESET_ALL}")
|
||||||
|
return
|
||||||
|
else:
|
||||||
|
print(f"{Fore.GREEN}{EMOJI['SUCCESS']} {translator.get('updater.up_to_date')}{Style.RESET_ALL}")
|
||||||
|
|
||||||
|
except requests.exceptions.RequestException as e:
|
||||||
|
print(f"{Fore.RED}{EMOJI['ERROR']} {translator.get('updater.network_error', error=str(e))}{Style.RESET_ALL}")
|
||||||
|
print(f"{Fore.YELLOW}{EMOJI['INFO']} {translator.get('updater.continue_anyway')}{Style.RESET_ALL}")
|
||||||
|
return
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
print(f"{Fore.RED}{EMOJI['ERROR']} {translator.get('updater.check_failed', error=str(e))}{Style.RESET_ALL}")
|
||||||
|
print(f"{Fore.YELLOW}{EMOJI['INFO']} {translator.get('updater.continue_anyway')}{Style.RESET_ALL}")
|
||||||
|
return
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
print_logo()
|
print_logo()
|
||||||
|
check_latest_version() # Add version check before showing menu
|
||||||
print_menu()
|
print_menu()
|
||||||
|
|
||||||
while True:
|
while True:
|
||||||
|
|||||||
340
new_signup.py
340
new_signup.py
@@ -4,6 +4,9 @@ import os
|
|||||||
import signal
|
import signal
|
||||||
import random
|
import random
|
||||||
from colorama import Fore, Style
|
from colorama import Fore, Style
|
||||||
|
import configparser
|
||||||
|
from pathlib import Path
|
||||||
|
import sys
|
||||||
|
|
||||||
# 在文件开头添加全局变量
|
# 在文件开头添加全局变量
|
||||||
_translator = None
|
_translator = None
|
||||||
@@ -94,40 +97,181 @@ def fill_signup_form(page, first_name, last_name, email, translator=None):
|
|||||||
print(f"填写表单时出错: {e}")
|
print(f"填写表单时出错: {e}")
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def setup_driver(translator=None):
|
def get_default_chrome_path():
|
||||||
"""设置浏览器驱动"""
|
"""Get default Chrome path"""
|
||||||
co = ChromiumOptions()
|
if sys.platform == "win32":
|
||||||
|
paths = [
|
||||||
# 使用无痕模式
|
os.path.join(os.environ.get('PROGRAMFILES', ''), 'Google/Chrome/Application/chrome.exe'),
|
||||||
co.set_argument("--incognito")
|
os.path.join(os.environ.get('PROGRAMFILES(X86)', ''), 'Google/Chrome/Application/chrome.exe'),
|
||||||
|
os.path.join(os.environ.get('LOCALAPPDATA', ''), 'Google/Chrome/Application/chrome.exe')
|
||||||
# 设置随机端口
|
]
|
||||||
co.auto_port()
|
elif sys.platform == "darwin":
|
||||||
|
paths = [
|
||||||
# 使用有头模式(一定要设置为False,模擬人類操作)
|
"/Applications/Google Chrome.app/Contents/MacOS/Google Chrome"
|
||||||
co.headless(False)
|
]
|
||||||
|
else: # Linux
|
||||||
|
paths = [
|
||||||
|
"/usr/bin/google-chrome",
|
||||||
|
"/usr/bin/google-chrome-stable"
|
||||||
|
]
|
||||||
|
|
||||||
|
for path in paths:
|
||||||
|
if os.path.exists(path):
|
||||||
|
return path
|
||||||
|
return ""
|
||||||
|
|
||||||
|
def get_user_documents_path():
|
||||||
|
"""Get user Documents folder path"""
|
||||||
|
if sys.platform == "win32":
|
||||||
|
return os.path.join(os.path.expanduser("~"), "Documents")
|
||||||
|
elif sys.platform == "darwin":
|
||||||
|
return os.path.join(os.path.expanduser("~"), "Documents")
|
||||||
|
else: # Linux
|
||||||
|
# Get actual user's home directory
|
||||||
|
sudo_user = os.environ.get('SUDO_USER')
|
||||||
|
if sudo_user:
|
||||||
|
return os.path.join("/home", sudo_user, "Documents")
|
||||||
|
return os.path.join(os.path.expanduser("~"), "Documents")
|
||||||
|
|
||||||
|
def parse_random_time(time_str):
|
||||||
|
"""解析随机时间范围配置"""
|
||||||
try:
|
try:
|
||||||
# 加载插件
|
if '-' in time_str:
|
||||||
extension_path = os.path.join(os.getcwd(), "turnstilePatch")
|
min_time, max_time = map(float, time_str.split('-'))
|
||||||
if os.path.exists(extension_path):
|
elif ',' in time_str:
|
||||||
co.set_argument("--allow-extensions-in-incognito")
|
min_time, max_time = map(float, time_str.split(','))
|
||||||
co.add_extension(extension_path)
|
else:
|
||||||
|
min_time = max_time = float(time_str)
|
||||||
|
return min_time, max_time
|
||||||
|
except:
|
||||||
|
return 1, 3 # 默认值
|
||||||
|
|
||||||
|
def setup_config(translator=None):
|
||||||
|
"""Setup configuration file and return config object"""
|
||||||
|
try:
|
||||||
|
# Set configuration file path
|
||||||
|
config_dir = os.path.join(get_user_documents_path(), ".cursor-free-vip")
|
||||||
|
config_file = os.path.join(config_dir, "config.ini")
|
||||||
|
|
||||||
|
# Create config directory (if it doesn't exist)
|
||||||
|
os.makedirs(config_dir, exist_ok=True)
|
||||||
|
|
||||||
|
# Read or create configuration file
|
||||||
|
config = configparser.ConfigParser()
|
||||||
|
|
||||||
|
# 默认配置
|
||||||
|
default_config = {
|
||||||
|
'Chrome': {
|
||||||
|
'chromepath': get_default_chrome_path()
|
||||||
|
},
|
||||||
|
'Turnstile': {
|
||||||
|
'handle_turnstile_time': '2',
|
||||||
|
'handle_turnstile_random_time': '1-3'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if os.path.exists(config_file):
|
||||||
|
config.read(config_file)
|
||||||
|
config_modified = False
|
||||||
|
|
||||||
|
# 检查并添加缺失的配置项
|
||||||
|
for section, options in default_config.items():
|
||||||
|
if not config.has_section(section):
|
||||||
|
config.add_section(section)
|
||||||
|
config_modified = True
|
||||||
|
for option, value in options.items():
|
||||||
|
if not config.has_option(section, option):
|
||||||
|
config.set(section, option, value)
|
||||||
|
config_modified = True
|
||||||
|
if translator:
|
||||||
|
print(f"{Fore.YELLOW}ℹ️ {translator.get('register.config_option_added', option=f'{section}.{option}') if translator else f'添加配置项: {section}.{option}'}{Style.RESET_ALL}")
|
||||||
|
|
||||||
|
# 如果有新增配置项,保存文件
|
||||||
|
if config_modified:
|
||||||
|
with open(config_file, 'w', encoding='utf-8') as f:
|
||||||
|
config.write(f)
|
||||||
|
if translator:
|
||||||
|
print(f"{Fore.GREEN}✅ {translator.get('register.config_updated') if translator else '配置文件已更新'}{Style.RESET_ALL}")
|
||||||
|
else:
|
||||||
|
# 创建新配置文件
|
||||||
|
config = configparser.ConfigParser()
|
||||||
|
for section, options in default_config.items():
|
||||||
|
config.add_section(section)
|
||||||
|
for option, value in options.items():
|
||||||
|
config.set(section, option, value)
|
||||||
|
|
||||||
|
with open(config_file, 'w', encoding='utf-8') as f:
|
||||||
|
config.write(f)
|
||||||
|
if translator:
|
||||||
|
print(f"{Fore.GREEN}✅ {translator.get('register.config_created') if translator else '已创建配置文件'}: {config_file}{Style.RESET_ALL}")
|
||||||
|
|
||||||
|
return config
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
if translator:
|
if translator:
|
||||||
print(f"{Fore.RED}❌ {translator.get('register.extension_load_error', error=str(e))}{Style.RESET_ALL}")
|
print(f"{Fore.RED}❌ {translator.get('register.config_setup_error', error=str(e)) if translator else f'配置设置出错: {str(e)}'}{Style.RESET_ALL}")
|
||||||
else:
|
raise
|
||||||
print(f"加载插件失败: {e}")
|
|
||||||
|
|
||||||
if translator:
|
|
||||||
print(f"{Fore.CYAN}🚀 {translator.get('register.starting_browser')}{Style.RESET_ALL}")
|
|
||||||
else:
|
|
||||||
print("正在启动浏览器...")
|
|
||||||
page = ChromiumPage(co)
|
|
||||||
|
|
||||||
return page
|
|
||||||
|
|
||||||
def handle_turnstile(page, translator=None):
|
def setup_driver(translator=None):
|
||||||
|
"""Setup browser driver"""
|
||||||
|
try:
|
||||||
|
# 获取配置
|
||||||
|
config = setup_config(translator)
|
||||||
|
|
||||||
|
# Get Chrome path
|
||||||
|
chrome_path = config.get('Chrome', 'chromepath', fallback=get_default_chrome_path())
|
||||||
|
|
||||||
|
if not chrome_path or not os.path.exists(chrome_path):
|
||||||
|
if translator:
|
||||||
|
print(f"{Fore.YELLOW}⚠️ {translator.get('register.chrome_path_invalid') if translator else 'Chrome路径无效,使用默认路径'}{Style.RESET_ALL}")
|
||||||
|
chrome_path = get_default_chrome_path()
|
||||||
|
|
||||||
|
# Set browser options
|
||||||
|
co = ChromiumOptions()
|
||||||
|
|
||||||
|
# Set Chrome path
|
||||||
|
co.set_browser_path(chrome_path)
|
||||||
|
|
||||||
|
# Use incognito mode
|
||||||
|
co.set_argument("--incognito")
|
||||||
|
|
||||||
|
# 设置随机端口
|
||||||
|
co.set_argument("--no-sandbox")
|
||||||
|
|
||||||
|
# 设置随机端口
|
||||||
|
co.auto_port()
|
||||||
|
|
||||||
|
# 使用有头模式(一定要设置为False,模拟人类操作)
|
||||||
|
co.headless(False)
|
||||||
|
|
||||||
|
try:
|
||||||
|
# 加载插件
|
||||||
|
extension_path = os.path.join(os.getcwd(), "turnstilePatch")
|
||||||
|
if os.path.exists(extension_path):
|
||||||
|
co.set_argument("--allow-extensions-in-incognito")
|
||||||
|
co.add_extension(extension_path)
|
||||||
|
except Exception as e:
|
||||||
|
if translator:
|
||||||
|
print(f"{Fore.RED}❌ {translator.get('register.extension_load_error', error=str(e))}{Style.RESET_ALL}")
|
||||||
|
else:
|
||||||
|
print(f"加载插件失败: {e}")
|
||||||
|
|
||||||
|
if translator:
|
||||||
|
print(f"{Fore.CYAN}🚀 {translator.get('register.starting_browser')}{Style.RESET_ALL}")
|
||||||
|
else:
|
||||||
|
print("正在启动浏览器...")
|
||||||
|
|
||||||
|
page = ChromiumPage(co)
|
||||||
|
return config, page
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
if translator:
|
||||||
|
print(f"{Fore.RED}❌ {translator.get('register.browser_setup_error', error=str(e))}{Style.RESET_ALL}")
|
||||||
|
else:
|
||||||
|
print(f"设置浏览器时出错: {e}")
|
||||||
|
raise
|
||||||
|
|
||||||
|
def handle_turnstile(page, config, translator=None):
|
||||||
"""处理 Turnstile 验证"""
|
"""处理 Turnstile 验证"""
|
||||||
try:
|
try:
|
||||||
if translator:
|
if translator:
|
||||||
@@ -135,6 +279,11 @@ def handle_turnstile(page, translator=None):
|
|||||||
else:
|
else:
|
||||||
print("\n正在处理 Turnstile 验证...")
|
print("\n正在处理 Turnstile 验证...")
|
||||||
|
|
||||||
|
# from config
|
||||||
|
turnstile_time = float(config.get('Turnstile', 'handle_turnstile_time', fallback='2'))
|
||||||
|
random_time_str = config.get('Turnstile', 'handle_turnstile_random_time', fallback='1-3')
|
||||||
|
min_random_time, max_random_time = parse_random_time(random_time_str)
|
||||||
|
|
||||||
max_retries = 2
|
max_retries = 2
|
||||||
retry_count = 0
|
retry_count = 0
|
||||||
|
|
||||||
@@ -148,7 +297,7 @@ def handle_turnstile(page, translator=None):
|
|||||||
try:
|
try:
|
||||||
# 尝试重置 turnstile
|
# 尝试重置 turnstile
|
||||||
page.run_js("try { turnstile.reset() } catch(e) { }")
|
page.run_js("try { turnstile.reset() } catch(e) { }")
|
||||||
time.sleep(2)
|
time.sleep(turnstile_time) # from config
|
||||||
|
|
||||||
# 定位验证框元素
|
# 定位验证框元素
|
||||||
challenge_check = (
|
challenge_check = (
|
||||||
@@ -165,12 +314,12 @@ def handle_turnstile(page, translator=None):
|
|||||||
else:
|
else:
|
||||||
print("检测到验证框...")
|
print("检测到验证框...")
|
||||||
|
|
||||||
# 随机延时后点击验证
|
# from config
|
||||||
time.sleep(random.uniform(1, 3))
|
time.sleep(random.uniform(min_random_time, max_random_time))
|
||||||
challenge_check.click()
|
challenge_check.click()
|
||||||
time.sleep(2)
|
time.sleep(turnstile_time) # from config
|
||||||
|
|
||||||
# 检查验证结果
|
# check verification result
|
||||||
if check_verification_success(page, translator):
|
if check_verification_success(page, translator):
|
||||||
if translator:
|
if translator:
|
||||||
print(f"{Fore.GREEN}✅ {translator.get('register.verification_success')}{Style.RESET_ALL}")
|
print(f"{Fore.GREEN}✅ {translator.get('register.verification_success')}{Style.RESET_ALL}")
|
||||||
@@ -192,7 +341,7 @@ def handle_turnstile(page, translator=None):
|
|||||||
print("验证通过!")
|
print("验证通过!")
|
||||||
return True
|
return True
|
||||||
|
|
||||||
time.sleep(random.uniform(1, 2))
|
time.sleep(random.uniform(min_random_time, max_random_time))
|
||||||
|
|
||||||
if translator:
|
if translator:
|
||||||
print(f"{Fore.RED}❌ {translator.get('register.verification_failed')}{Style.RESET_ALL}")
|
print(f"{Fore.RED}❌ {translator.get('register.verification_failed')}{Style.RESET_ALL}")
|
||||||
@@ -237,34 +386,51 @@ def generate_password(length=12):
|
|||||||
chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!@#$%^&*"
|
chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!@#$%^&*"
|
||||||
return ''.join(random.choices(chars, k=length))
|
return ''.join(random.choices(chars, k=length))
|
||||||
|
|
||||||
def fill_password(page, password, translator=None):
|
def fill_password(page, password: str, translator=None) -> bool:
|
||||||
"""填写密码"""
|
"""
|
||||||
|
填写密码表单
|
||||||
|
"""
|
||||||
try:
|
try:
|
||||||
if translator:
|
print(f"{Fore.CYAN}🔑 {translator.get('register.setting_password') if translator else '设置密码'}{Style.RESET_ALL}")
|
||||||
print(f"{Fore.CYAN}🔑 {translator.get('register.setting_password')}{Style.RESET_ALL}")
|
|
||||||
else:
|
# 等待密码框出现
|
||||||
print(f"\n{translator.get('register.setting_password')}")
|
max_retries = 5
|
||||||
password_input = page.ele("@name=password")
|
for i in range(max_retries):
|
||||||
|
try:
|
||||||
|
# 使用 DrissionPage 的方式查找密码输入框
|
||||||
|
password_input = page.ele('@type=password', timeout=3)
|
||||||
|
if password_input:
|
||||||
|
break
|
||||||
|
time.sleep(2)
|
||||||
|
except:
|
||||||
|
if i == max_retries - 1:
|
||||||
|
print(f"{Fore.RED}❌ {translator.get('register.password_field_not_found') if translator else '未找到密码输入框'}{Style.RESET_ALL}")
|
||||||
|
return False
|
||||||
|
continue
|
||||||
|
|
||||||
if password_input:
|
if password_input:
|
||||||
|
# 清除可能存在的旧值
|
||||||
|
password_input.click()
|
||||||
|
time.sleep(0.5)
|
||||||
password_input.input(password)
|
password_input.input(password)
|
||||||
time.sleep(random.uniform(0.5, 1.0))
|
time.sleep(1)
|
||||||
|
|
||||||
submit_button = page.ele("@type=submit")
|
# 查找并点击提交按钮
|
||||||
|
submit_button = page.ele('@type=submit')
|
||||||
if submit_button:
|
if submit_button:
|
||||||
submit_button.click()
|
submit_button.click()
|
||||||
time.sleep(random.uniform(2.0, 3.0))
|
time.sleep(2)
|
||||||
|
return True
|
||||||
if translator:
|
|
||||||
print(f"{Fore.GREEN}✅ {translator.get('register.password_success')}{Style.RESET_ALL}")
|
|
||||||
else:
|
else:
|
||||||
print(f"{translator.get('register.password_success')}: {password}")
|
print(f"{Fore.RED}❌ {translator.get('register.continue_button_not_found') if translator else '未找到继续按钮'}{Style.RESET_ALL}")
|
||||||
return True
|
return False
|
||||||
|
|
||||||
except Exception as e:
|
|
||||||
if translator:
|
|
||||||
print(f"{Fore.RED}❌ {translator.get('register.password_error', error=str(e))}{Style.RESET_ALL}")
|
|
||||||
else:
|
else:
|
||||||
print(f"{translator.get('register.password_error')}: {e}")
|
print(f"{Fore.RED}❌ {translator.get('register.password_input_failed') if translator else '密码输入失败'}{Style.RESET_ALL}")
|
||||||
|
return False
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
print(f"{Fore.RED}❌ {translator.get('register.password_setting_error', error=str(e)) if translator else f'设置密码时出错: {str(e)}'}{Style.RESET_ALL}")
|
||||||
|
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def handle_verification_code(browser_tab, email_tab, controller, email, password, translator=None):
|
def handle_verification_code(browser_tab, email_tab, controller, email, password, translator=None):
|
||||||
@@ -272,8 +438,6 @@ def handle_verification_code(browser_tab, email_tab, controller, email, password
|
|||||||
try:
|
try:
|
||||||
if translator:
|
if translator:
|
||||||
print(f"\n{Fore.CYAN}{translator.get('register.waiting_for_verification_code')}{Style.RESET_ALL}")
|
print(f"\n{Fore.CYAN}{translator.get('register.waiting_for_verification_code')}{Style.RESET_ALL}")
|
||||||
else:
|
|
||||||
print(f"\n{translator.get('register.waiting_for_verification_code')}")
|
|
||||||
|
|
||||||
# 检查是否使用手动输入验证码
|
# 检查是否使用手动输入验证码
|
||||||
if hasattr(controller, 'get_verification_code') and email_tab is None: # 手动模式
|
if hasattr(controller, 'get_verification_code') and email_tab is None: # 手动模式
|
||||||
@@ -290,13 +454,11 @@ def handle_verification_code(browser_tab, email_tab, controller, email, password
|
|||||||
# 处理最后一次 Turnstile 验证
|
# 处理最后一次 Turnstile 验证
|
||||||
if handle_turnstile(browser_tab, translator):
|
if handle_turnstile(browser_tab, translator):
|
||||||
if translator:
|
if translator:
|
||||||
print(f"{translator.get('register.verification_success')}")
|
print(f"{Fore.GREEN}✅ {translator.get('register.verification_success')}{Style.RESET_ALL}")
|
||||||
else:
|
|
||||||
print(f"{translator.get('register.verification_success')}")
|
|
||||||
time.sleep(2)
|
time.sleep(2)
|
||||||
|
|
||||||
# 访问设置页面
|
# 访问设置页面
|
||||||
print(f"{translator.get('register.visiting_url')}: https://www.cursor.com/settings")
|
print(f"{Fore.CYAN} {translator.get('register.visiting_url')}: https://www.cursor.com/settings{Style.RESET_ALL}")
|
||||||
browser_tab.get("https://www.cursor.com/settings")
|
browser_tab.get("https://www.cursor.com/settings")
|
||||||
time.sleep(3) # 等待页面加载
|
time.sleep(3) # 等待页面加载
|
||||||
return True, browser_tab
|
return True, browser_tab
|
||||||
@@ -322,23 +484,17 @@ def handle_verification_code(browser_tab, email_tab, controller, email, password
|
|||||||
time.sleep(random.uniform(0.1, 0.3))
|
time.sleep(random.uniform(0.1, 0.3))
|
||||||
if translator:
|
if translator:
|
||||||
print(f"{Fore.GREEN}✅ {translator.get('register.verification_success')}{Style.RESET_ALL}")
|
print(f"{Fore.GREEN}✅ {translator.get('register.verification_success')}{Style.RESET_ALL}")
|
||||||
else:
|
|
||||||
print("验证码填写完成")
|
|
||||||
time.sleep(3)
|
time.sleep(3)
|
||||||
|
|
||||||
# 处理最后一次 Turnstile 验证
|
# 处理最后一次 Turnstile 验证
|
||||||
if handle_turnstile(browser_tab, translator):
|
if handle_turnstile(browser_tab, translator):
|
||||||
if translator:
|
if translator:
|
||||||
print(f"{Fore.GREEN}✅ {translator.get('register.verification_success')}{Style.RESET_ALL}")
|
print(f"{Fore.GREEN}✅ {translator.get('register.verification_success')}{Style.RESET_ALL}")
|
||||||
else:
|
|
||||||
print("最后一次验证通过!")
|
|
||||||
time.sleep(2)
|
time.sleep(2)
|
||||||
|
|
||||||
# 访问设置页面
|
# 访问设置页面
|
||||||
if translator:
|
if translator:
|
||||||
print(f"{Fore.CYAN}🔑 {translator.get('register.visiting_url')}: https://www.cursor.com/settings{Style.RESET_ALL}")
|
print(f"{Fore.CYAN}🔑 {translator.get('register.visiting_url')}: https://www.cursor.com/settings{Style.RESET_ALL}")
|
||||||
else:
|
|
||||||
print("访问设置页面...")
|
|
||||||
browser_tab.get("https://www.cursor.com/settings")
|
browser_tab.get("https://www.cursor.com/settings")
|
||||||
time.sleep(3) # 等待页面加载
|
time.sleep(3) # 等待页面加载
|
||||||
return True, browser_tab
|
return True, browser_tab
|
||||||
@@ -359,31 +515,23 @@ def handle_verification_code(browser_tab, email_tab, controller, email, password
|
|||||||
|
|
||||||
if translator:
|
if translator:
|
||||||
print(f"{Fore.CYAN}{translator.get('register.start_getting_verification_code')}{Style.RESET_ALL}")
|
print(f"{Fore.CYAN}{translator.get('register.start_getting_verification_code')}{Style.RESET_ALL}")
|
||||||
else:
|
|
||||||
print("开始获取验证码...")
|
|
||||||
|
|
||||||
for attempt in range(max_attempts):
|
for attempt in range(max_attempts):
|
||||||
# 检查是否超时
|
# 检查是否超时
|
||||||
if time.time() - start_time > timeout:
|
if time.time() - start_time > timeout:
|
||||||
if translator:
|
if translator:
|
||||||
print(f"{Fore.RED}❌ {translator.get('register.verification_timeout')}{Style.RESET_ALL}")
|
print(f"{Fore.RED}❌ {translator.get('register.verification_timeout')}{Style.RESET_ALL}")
|
||||||
else:
|
|
||||||
print("获取验证码超时...")
|
|
||||||
break
|
break
|
||||||
|
|
||||||
verification_code = controller.get_verification_code()
|
verification_code = controller.get_verification_code()
|
||||||
if verification_code:
|
if verification_code:
|
||||||
if translator:
|
if translator:
|
||||||
print(f"{Fore.GREEN}✅ {translator.get('register.verification_success')}{Style.RESET_ALL}")
|
print(f"{Fore.GREEN}✅ {translator.get('register.verification_success')}{Style.RESET_ALL}")
|
||||||
else:
|
|
||||||
print(f"成功获取验证码: {verification_code}")
|
|
||||||
break
|
break
|
||||||
|
|
||||||
remaining_time = int(timeout - (time.time() - start_time))
|
remaining_time = int(timeout - (time.time() - start_time))
|
||||||
if translator:
|
if translator:
|
||||||
print(f"{Fore.CYAN}{translator.get('register.try_get_code', attempt=attempt + 1, time=remaining_time)}{Style.RESET_ALL}")
|
print(f"{Fore.CYAN}{translator.get('register.try_get_code', attempt=attempt + 1, time=remaining_time)}{Style.RESET_ALL}")
|
||||||
else:
|
|
||||||
print(f"第 {attempt + 1} 次尝试获取验证码,剩余时间: {remaining_time}秒...")
|
|
||||||
|
|
||||||
# 刷新邮箱
|
# 刷新邮箱
|
||||||
email_tab.refresh_inbox()
|
email_tab.refresh_inbox()
|
||||||
@@ -397,23 +545,17 @@ def handle_verification_code(browser_tab, email_tab, controller, email, password
|
|||||||
|
|
||||||
if translator:
|
if translator:
|
||||||
print(f"{Fore.GREEN}✅ {translator.get('register.verification_success')}{Style.RESET_ALL}")
|
print(f"{Fore.GREEN}✅ {translator.get('register.verification_success')}{Style.RESET_ALL}")
|
||||||
else:
|
|
||||||
print("验证码填写完成")
|
|
||||||
time.sleep(3)
|
time.sleep(3)
|
||||||
|
|
||||||
# 处理最后一次 Turnstile 验证
|
# 处理最后一次 Turnstile 验证
|
||||||
if handle_turnstile(browser_tab, translator):
|
if handle_turnstile(browser_tab, translator):
|
||||||
if translator:
|
if translator:
|
||||||
print(f"{Fore.GREEN}✅ {translator.get('register.verification_success')}{Style.RESET_ALL}")
|
print(f"{Fore.GREEN}✅ {translator.get('register.verification_success')}{Style.RESET_ALL}")
|
||||||
else:
|
|
||||||
print("最后一次验证通过!")
|
|
||||||
time.sleep(2)
|
time.sleep(2)
|
||||||
|
|
||||||
# 直接访问设置页面
|
# 直接访问设置页面
|
||||||
if translator:
|
if translator:
|
||||||
print(f"{Fore.CYAN}{translator.get('register.visiting_url')}: https://www.cursor.com/settings{Style.RESET_ALL}")
|
print(f"{Fore.CYAN}{translator.get('register.visiting_url')}: https://www.cursor.com/settings{Style.RESET_ALL}")
|
||||||
else:
|
|
||||||
print("访问设置页面...")
|
|
||||||
browser_tab.get("https://www.cursor.com/settings")
|
browser_tab.get("https://www.cursor.com/settings")
|
||||||
time.sleep(3) # 等待页面加载
|
time.sleep(3) # 等待页面加载
|
||||||
|
|
||||||
@@ -423,8 +565,6 @@ def handle_verification_code(browser_tab, email_tab, controller, email, password
|
|||||||
else:
|
else:
|
||||||
if translator:
|
if translator:
|
||||||
print(f"{Fore.RED}❌ {translator.get('register.verification_failed')}{Style.RESET_ALL}")
|
print(f"{Fore.RED}❌ {translator.get('register.verification_failed')}{Style.RESET_ALL}")
|
||||||
else:
|
|
||||||
print("最后一次验证失败")
|
|
||||||
return False, None
|
return False, None
|
||||||
|
|
||||||
return False, None
|
return False, None
|
||||||
@@ -432,8 +572,6 @@ def handle_verification_code(browser_tab, email_tab, controller, email, password
|
|||||||
except Exception as e:
|
except Exception as e:
|
||||||
if translator:
|
if translator:
|
||||||
print(f"{Fore.RED}❌ {translator.get('register.verification_error', error=str(e))}{Style.RESET_ALL}")
|
print(f"{Fore.RED}❌ {translator.get('register.verification_error', error=str(e))}{Style.RESET_ALL}")
|
||||||
else:
|
|
||||||
print(f"处理验证码时出错: {e}")
|
|
||||||
return False, None
|
return False, None
|
||||||
|
|
||||||
def handle_sign_in(browser_tab, email, password, translator=None):
|
def handle_sign_in(browser_tab, email, password, translator=None):
|
||||||
@@ -496,25 +634,19 @@ def main(email=None, password=None, first_name=None, last_name=None, email_tab=N
|
|||||||
page = None
|
page = None
|
||||||
success = False
|
success = False
|
||||||
try:
|
try:
|
||||||
page = setup_driver(translator)
|
config, page = setup_driver(translator)
|
||||||
if translator:
|
if translator:
|
||||||
print(f"{Fore.CYAN}🚀 {translator.get('register.browser_started')}{Style.RESET_ALL}")
|
print(f"{Fore.CYAN}🚀 {translator.get('register.browser_started')}{Style.RESET_ALL}")
|
||||||
else:
|
|
||||||
print("浏览器已启动")
|
|
||||||
|
|
||||||
# 访问注册页面
|
# 访问注册页面
|
||||||
url = "https://authenticator.cursor.sh/sign-up"
|
url = "https://authenticator.cursor.sh/sign-up"
|
||||||
if translator:
|
if translator:
|
||||||
print(f"\n{Fore.CYAN}{translator.get('register.visiting_url')}: {url}{Style.RESET_ALL}")
|
print(f"\n{Fore.CYAN}{translator.get('register.visiting_url')}: {url}{Style.RESET_ALL}")
|
||||||
else:
|
|
||||||
print(f"\n正在访问: {url}")
|
|
||||||
|
|
||||||
# 访问页面
|
# 访问页面
|
||||||
simulate_human_input(page, url, translator)
|
simulate_human_input(page, url, translator)
|
||||||
if translator:
|
if translator:
|
||||||
print(f"{Fore.CYAN}{translator.get('register.waiting_for_page_load')}{Style.RESET_ALL}")
|
print(f"{Fore.CYAN}{translator.get('register.waiting_for_page_load')}{Style.RESET_ALL}")
|
||||||
else:
|
|
||||||
print("等待页面加载...")
|
|
||||||
time.sleep(5)
|
time.sleep(5)
|
||||||
|
|
||||||
# 如果没有提供账号信息,则生成随机信息
|
# 如果没有提供账号信息,则生成随机信息
|
||||||
@@ -535,41 +667,33 @@ def main(email=None, password=None, first_name=None, last_name=None, email_tab=N
|
|||||||
if fill_signup_form(page, first_name, last_name, email, translator):
|
if fill_signup_form(page, first_name, last_name, email, translator):
|
||||||
if translator:
|
if translator:
|
||||||
print(f"\n{Fore.GREEN}{translator.get('register.form_submitted')}{Style.RESET_ALL}")
|
print(f"\n{Fore.GREEN}{translator.get('register.form_submitted')}{Style.RESET_ALL}")
|
||||||
else:
|
|
||||||
print("\n表单已提交,开始验证...")
|
|
||||||
|
|
||||||
# 处理第一次 Turnstile 验证
|
# 处理第一次 Turnstile 验证
|
||||||
if handle_turnstile(page, translator):
|
if handle_turnstile(page, config, translator):
|
||||||
if translator:
|
if translator:
|
||||||
print(f"\n{Fore.GREEN}{translator.get('register.first_verification_passed')}{Style.RESET_ALL}")
|
print(f"\n{Fore.GREEN}{translator.get('register.first_verification_passed')}{Style.RESET_ALL}")
|
||||||
else:
|
|
||||||
print("\n第一阶段验证通过!")
|
|
||||||
|
|
||||||
# 填写密码
|
# 填写密码
|
||||||
if fill_password(page, password, translator):
|
if fill_password(page, password, translator):
|
||||||
if translator:
|
if translator:
|
||||||
print(f"\n{Fore.CYAN}{translator.get('register.waiting_for_second_verification')}{Style.RESET_ALL}")
|
print(f"\n{Fore.CYAN}{translator.get('register.waiting_for_second_verification')}{Style.RESET_ALL}")
|
||||||
else:
|
|
||||||
print("\n等待第二次验证...")
|
|
||||||
time.sleep(2)
|
time.sleep(2)
|
||||||
|
|
||||||
# 处理第二次 Turnstile 验证
|
# 处理第二次 Turnstile 验证
|
||||||
if handle_turnstile(page, translator):
|
if handle_turnstile(page, config, translator):
|
||||||
if translator:
|
if translator:
|
||||||
print(f"\n{Fore.CYAN}{translator.get('register.waiting_for_verification_code')}{Style.RESET_ALL}")
|
print(f"\n{Fore.CYAN}{translator.get('register.waiting_for_verification_code')}{Style.RESET_ALL}")
|
||||||
else:
|
|
||||||
print("\n开始处理验证码...")
|
|
||||||
if handle_verification_code(page, email_tab, controller, email, password, translator):
|
if handle_verification_code(page, email_tab, controller, email, password, translator):
|
||||||
success = True
|
success = True
|
||||||
return True, page # 返回浏览器实例
|
return True, page # 返回浏览器实例
|
||||||
else:
|
else:
|
||||||
print("\n验证码处理失败")
|
print(f"\n{Fore.RED} {translator.get('register.verification_code_processing_failed') if translator else '验证码处理失败'}{Style.RESET_ALL}")
|
||||||
else:
|
else:
|
||||||
print("\n第二次验证失败")
|
print(f"\n{Fore.RED} {translator.get('register.second_verification_failed') if translator else '第二次验证失败'}{Style.RESET_ALL}")
|
||||||
else:
|
else:
|
||||||
print("\n密码设置失败")
|
print(f"\n{Fore.RED} {translator.get('register.second_verification_failed') if translator else '第二次验证失败'}{Style.RESET_ALL}")
|
||||||
else:
|
else:
|
||||||
print("\n第一次验证失败")
|
print(f"\n{Fore.RED} {translator.get('register.first_verification_failed') if translator else '第一次验证失败'}{Style.RESET_ALL}")
|
||||||
|
|
||||||
return False, None
|
return False, None
|
||||||
|
|
||||||
|
|||||||
296
new_tempemail.py
296
new_tempemail.py
@@ -7,7 +7,7 @@ import requests
|
|||||||
import random
|
import random
|
||||||
import string
|
import string
|
||||||
|
|
||||||
# 初始化 colorama
|
# Initialize colorama
|
||||||
init()
|
init()
|
||||||
|
|
||||||
class NewTempEmail:
|
class NewTempEmail:
|
||||||
@@ -34,7 +34,7 @@ class NewTempEmail:
|
|||||||
# Split text and remove empty lines
|
# Split text and remove empty lines
|
||||||
domains = [line.strip() for line in response.text.split('\n') if line.strip()]
|
domains = [line.strip() for line in response.text.split('\n') if line.strip()]
|
||||||
if self.translator:
|
if self.translator:
|
||||||
print(f"{Fore.CYAN}ℹ️ {self.translator.get('email.blocked_domains_loaded', count=len(domains))}{Style.RESET_ALL}")
|
print(f"{Fore.CYAN}ℹ️ {self.translator.get('email.blocked_domains_loaded', count=len(domains))}{Style.RESET_ALL}")
|
||||||
else:
|
else:
|
||||||
print(f"{Fore.CYAN}ℹ️ 已加载 {len(domains)} 个被屏蔽的域名{Style.RESET_ALL}")
|
print(f"{Fore.CYAN}ℹ️ 已加载 {len(domains)} 个被屏蔽的域名{Style.RESET_ALL}")
|
||||||
return domains
|
return domains
|
||||||
@@ -66,153 +66,179 @@ class NewTempEmail:
|
|||||||
return filtered_domains
|
return filtered_domains
|
||||||
|
|
||||||
def _generate_credentials(self):
|
def _generate_credentials(self):
|
||||||
"""生成随机用户名和密码"""
|
"""generate random username and password"""
|
||||||
username = ''.join(random.choices(string.ascii_lowercase + string.digits, k=10))
|
username = ''.join(random.choices(string.ascii_lowercase + string.digits, k=10))
|
||||||
password = ''.join(random.choices(string.ascii_letters + string.digits + string.punctuation, k=12))
|
password = ''.join(random.choices(string.ascii_letters + string.digits + string.punctuation, k=12))
|
||||||
return username, password
|
return username, password
|
||||||
|
|
||||||
def create_email(self):
|
def create_email(self):
|
||||||
"""创建临时邮箱"""
|
"""create temporary email"""
|
||||||
try:
|
max_retries = 3 # Maximum number of retries
|
||||||
if self.translator:
|
attempt = 0 # Current attempt count
|
||||||
print(f"{Fore.CYAN}ℹ️ {self.translator.get('email.visiting_site').replace('mail.tm', self.selected_service['name'])}{Style.RESET_ALL}")
|
|
||||||
else:
|
while attempt < max_retries:
|
||||||
print(f"{Fore.CYAN}ℹ️ 正在访问 {self.selected_service['name']}...{Style.RESET_ALL}")
|
attempt += 1
|
||||||
|
|
||||||
# 获取可用域名列表
|
|
||||||
try:
|
try:
|
||||||
domains_response = requests.get(f"{self.api_url}/domains", timeout=10)
|
|
||||||
if domains_response.status_code != 200:
|
|
||||||
print(f"{Fore.RED}❌ {self.translator.get('email.domains_list_error', error=domains_response.status_code)}{Style.RESET_ALL}")
|
|
||||||
print(f"{Fore.RED}❌ {self.translator.get('email.domains_list_error', error=domains_response.text)}{Style.RESET_ALL}")
|
|
||||||
raise Exception(f"{self.translator.get('email.failed_to_get_available_domains') if self.translator else 'Failed to get available domains'}")
|
|
||||||
|
|
||||||
domains = domains_response.json()["hydra:member"]
|
|
||||||
print(f"{Fore.CYAN}ℹ️ {self.translator.get('email.available_domains_loaded', count=len(domains))}{Style.RESET_ALL}")
|
|
||||||
|
|
||||||
if not domains:
|
|
||||||
raise Exception(f"{self.translator.get('email.no_available_domains') if self.translator else '没有可用域名'}")
|
|
||||||
except Exception as e:
|
|
||||||
print(f"{Fore.RED}❌ 获取域名列表时出错: {str(e)}{Style.RESET_ALL}")
|
|
||||||
raise
|
|
||||||
|
|
||||||
# 排除被屏蔽的域名
|
|
||||||
try:
|
|
||||||
filtered_domains = self.exclude_blocked_domains(domains)
|
|
||||||
if self.translator:
|
if self.translator:
|
||||||
print(f"{Fore.CYAN}ℹ️ {self.translator.get('email.domains_filtered', count=len(filtered_domains))}{Style.RESET_ALL}")
|
print(f"{Fore.CYAN}ℹ️ {self.translator.get('email.visiting_site').replace('mail.tm', self.selected_service['name'])}{Style.RESET_ALL}")
|
||||||
else:
|
else:
|
||||||
print(f"{Fore.CYAN}ℹ️ 过滤后剩余 {len(filtered_domains)} 个可用域名{Style.RESET_ALL}")
|
print(f"{Fore.CYAN}ℹ️ 正在访问 {self.selected_service['name']}...{Style.RESET_ALL}")
|
||||||
|
|
||||||
if not filtered_domains:
|
# Get available domain list
|
||||||
|
try:
|
||||||
|
domains_response = requests.get(f"{self.api_url}/domains", timeout=10)
|
||||||
|
if domains_response.status_code != 200:
|
||||||
|
print(f"{Fore.RED}❌ {self.translator.get('email.domains_list_error', error=domains_response.status_code)}{Style.RESET_ALL}")
|
||||||
|
print(f"{Fore.RED}❌ {self.translator.get('email.domains_list_error', error=domains_response.text)}{Style.RESET_ALL}")
|
||||||
|
raise Exception(f"{self.translator.get('email.failed_to_get_available_domains') if self.translator else 'Failed to get available domains'}")
|
||||||
|
|
||||||
|
domains = domains_response.json()["hydra:member"]
|
||||||
|
print(f"{Fore.CYAN}ℹ️ {self.translator.get('email.available_domains_loaded', count=len(domains))}{Style.RESET_ALL}")
|
||||||
|
|
||||||
|
if not domains:
|
||||||
|
raise Exception(f"{self.translator.get('email.no_available_domains') if self.translator else '没有可用域名'}")
|
||||||
|
except Exception as e:
|
||||||
|
print(f"{Fore.RED}❌ 获取域名列表时出错: {str(e)}{Style.RESET_ALL}")
|
||||||
|
raise
|
||||||
|
|
||||||
|
# Exclude blocked domains
|
||||||
|
try:
|
||||||
|
filtered_domains = self.exclude_blocked_domains(domains)
|
||||||
if self.translator:
|
if self.translator:
|
||||||
print(f"{Fore.RED}❌ {self.translator.get('email.all_domains_blocked')}{Style.RESET_ALL}")
|
print(f"{Fore.CYAN}ℹ️ {self.translator.get('email.domains_filtered', count=len(filtered_domains))}{Style.RESET_ALL}")
|
||||||
else:
|
else:
|
||||||
print(f"{Fore.RED}❌ 所有域名都被屏蔽了,尝试切换服务{Style.RESET_ALL}")
|
print(f"{Fore.CYAN}ℹ️ 过滤后剩余 {len(filtered_domains)} 个可用域名{Style.RESET_ALL}")
|
||||||
|
|
||||||
# 切换到另一个服务
|
if not filtered_domains:
|
||||||
for service in self.services:
|
if self.translator:
|
||||||
if service["api_url"] != self.api_url:
|
print(f"{Fore.RED}❌ {self.translator.get('email.all_domains_blocked')}{Style.RESET_ALL}")
|
||||||
self.selected_service = service
|
else:
|
||||||
self.api_url = service["api_url"]
|
print(f"{Fore.RED}❌ 所有域名都被屏蔽了,尝试切换服务{Style.RESET_ALL}")
|
||||||
if self.translator:
|
|
||||||
print(f"{Fore.CYAN}ℹ️ {self.translator.get('email.switching_service', service=service['name'])}{Style.RESET_ALL}")
|
# Switch to another service
|
||||||
else:
|
for service in self.services:
|
||||||
print(f"{Fore.CYAN}ℹ️ 切换到 {service['name']} 服务{Style.RESET_ALL}")
|
if service["api_url"] != self.api_url:
|
||||||
return self.create_email() # 递归调用
|
self.selected_service = service
|
||||||
|
self.api_url = service["api_url"]
|
||||||
raise Exception(f"{self.translator.get('email.no_available_domains_after_filtering') if self.translator else '过滤后没有可用域名'}")
|
if self.translator:
|
||||||
|
print(f"{Fore.CYAN}ℹ️ {self.translator.get('email.switching_service', service=service['name'])}{Style.RESET_ALL}")
|
||||||
|
else:
|
||||||
|
print(f"{Fore.CYAN}ℹ️ 切换到 {service['name']} 服务{Style.RESET_ALL}")
|
||||||
|
return self.create_email() # Recursively call
|
||||||
|
|
||||||
|
raise Exception(f"{self.translator.get('email.no_available_domains_after_filtering') if self.translator else '过滤后没有可用域名'}")
|
||||||
|
except Exception as e:
|
||||||
|
print(f"{Fore.RED}❌ 过滤域名时出错: {str(e)}{Style.RESET_ALL}")
|
||||||
|
raise
|
||||||
|
|
||||||
|
# Generate random username and password
|
||||||
|
try:
|
||||||
|
username, password = self._generate_credentials()
|
||||||
|
self.password = password
|
||||||
|
|
||||||
|
# Create email account
|
||||||
|
selected_domain = filtered_domains[0]['domain']
|
||||||
|
email = f"{username}@{selected_domain}"
|
||||||
|
|
||||||
|
if self.translator:
|
||||||
|
print(f"{Fore.CYAN}ℹ️ {self.translator.get('email.trying_to_create_email', email=email)}{Style.RESET_ALL}")
|
||||||
|
else:
|
||||||
|
print(f"{Fore.CYAN}ℹ️ 尝试创建邮箱: {email}{Style.RESET_ALL}")
|
||||||
|
|
||||||
|
account_data = {
|
||||||
|
"address": email,
|
||||||
|
"password": password
|
||||||
|
}
|
||||||
|
except Exception as e:
|
||||||
|
print(f"{Fore.RED}❌ 生成凭据时出错: {str(e)}{Style.RESET_ALL}")
|
||||||
|
raise
|
||||||
|
|
||||||
|
# Create account
|
||||||
|
try:
|
||||||
|
create_response = requests.post(f"{self.api_url}/accounts", json=account_data, timeout=15)
|
||||||
|
|
||||||
|
if create_response.status_code != 201:
|
||||||
|
if self.translator:
|
||||||
|
print(f"{Fore.RED}❌ {self.translator.get('email.failed_to_create_account', error=create_response.status_code)}{Style.RESET_ALL}")
|
||||||
|
else:
|
||||||
|
print(f"{Fore.RED}❌ 创建账户失败: 状态码 {create_response.status_code}{Style.RESET_ALL}")
|
||||||
|
if self.translator:
|
||||||
|
print(f"{Fore.RED}❌ {self.translator.get('email.failed_to_create_account', error=create_response.text)}{Style.RESET_ALL}")
|
||||||
|
else:
|
||||||
|
print(f"{Fore.RED}❌ 响应内容: {create_response.text}{Style.RESET_ALL}")
|
||||||
|
|
||||||
|
# If it's a domain problem, try the next available domain
|
||||||
|
if len(filtered_domains) > 1 and ("domain" in create_response.text.lower() or "address" in create_response.text.lower()):
|
||||||
|
print(f"{Fore.YELLOW}⚠️ 尝试使用下一个可用域名...{Style.RESET_ALL}")
|
||||||
|
# Add current domain to blocked list
|
||||||
|
if selected_domain not in self.blocked_domains:
|
||||||
|
self.blocked_domains.append(selected_domain)
|
||||||
|
# Recursively call yourself
|
||||||
|
return self.create_email()
|
||||||
|
|
||||||
|
raise Exception(f"{self.translator.get('email.failed_to_create_account') if self.translator else '创建账户失败'}")
|
||||||
|
except Exception as e:
|
||||||
|
if self.translator:
|
||||||
|
print(f"{Fore.RED}❌ {self.translator.get('email.failed_to_create_account', error=str(e))}{Style.RESET_ALL}")
|
||||||
|
else:
|
||||||
|
print(f"{Fore.RED}❌ 创建账户时出错: {str(e)}{Style.RESET_ALL}")
|
||||||
|
raise
|
||||||
|
|
||||||
|
# Get access token
|
||||||
|
try:
|
||||||
|
token_data = {
|
||||||
|
"address": email,
|
||||||
|
"password": password
|
||||||
|
}
|
||||||
|
|
||||||
|
token_response = requests.post(f"{self.api_url}/token", json=token_data, timeout=10)
|
||||||
|
if token_response.status_code != 200:
|
||||||
|
if self.translator:
|
||||||
|
print(f"{Fore.RED}❌ {self.translator.get('email.failed_to_get_access_token', error=token_response.status_code)}{Style.RESET_ALL}")
|
||||||
|
else:
|
||||||
|
print(f"{Fore.RED}❌ 获取令牌失败: 状态码 {token_response.status_code}{Style.RESET_ALL}")
|
||||||
|
if self.translator:
|
||||||
|
print(f"{Fore.RED}❌ {self.translator.get('email.failed_to_get_access_token', error=token_response.text)}{Style.RESET_ALL}")
|
||||||
|
else:
|
||||||
|
print(f"{Fore.RED}❌ 响应内容: {token_response.text}{Style.RESET_ALL}")
|
||||||
|
raise Exception(f"{self.translator.get('email.failed_to_get_access_token') if self.translator else '获取访问令牌失败'}")
|
||||||
|
|
||||||
|
self.token = token_response.json()["token"]
|
||||||
|
self.email = email
|
||||||
|
except Exception as e:
|
||||||
|
print(f"{Fore.RED}❌ 获取令牌时出错: {str(e)}{Style.RESET_ALL}")
|
||||||
|
raise
|
||||||
|
|
||||||
|
if self.translator:
|
||||||
|
print(f"{Fore.GREEN}✅ {self.translator.get('email.create_success')}: {email}{Style.RESET_ALL}")
|
||||||
|
else:
|
||||||
|
print(f"{Fore.GREEN}✅ 创建邮箱成功: {email}{Style.RESET_ALL}")
|
||||||
|
return email
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f"{Fore.RED}❌ 过滤域名时出错: {str(e)}{Style.RESET_ALL}")
|
if attempt < max_retries:
|
||||||
raise
|
print(f"{Fore.YELLOW}⚠️ 尝试重新创建邮箱... (尝试 {attempt}/{max_retries}){Style.RESET_ALL}")
|
||||||
|
else:
|
||||||
# 生成随机用户名和密码
|
if self.translator:
|
||||||
try:
|
print(f"{Fore.RED}❌ {self.translator.get('email.create_error')}: {str(e)}{Style.RESET_ALL}")
|
||||||
username, password = self._generate_credentials()
|
else:
|
||||||
self.password = password
|
print(f"{Fore.RED}❌ 创建邮箱出错: {str(e)}{Style.RESET_ALL}")
|
||||||
|
return None
|
||||||
# 创建邮箱账户
|
|
||||||
selected_domain = filtered_domains[0]['domain']
|
|
||||||
email = f"{username}@{selected_domain}"
|
|
||||||
|
|
||||||
print(f"{Fore.CYAN}ℹ️ 尝试创建邮箱: {email}{Style.RESET_ALL}")
|
|
||||||
|
|
||||||
account_data = {
|
|
||||||
"address": email,
|
|
||||||
"password": password
|
|
||||||
}
|
|
||||||
except Exception as e:
|
|
||||||
print(f"{Fore.RED}❌ 生成凭据时出错: {str(e)}{Style.RESET_ALL}")
|
|
||||||
raise
|
|
||||||
|
|
||||||
# 创建账户
|
|
||||||
try:
|
|
||||||
create_response = requests.post(f"{self.api_url}/accounts", json=account_data, timeout=15)
|
|
||||||
|
|
||||||
if create_response.status_code != 201:
|
|
||||||
print(f"{Fore.RED}❌ 创建账户失败: 状态码 {create_response.status_code}{Style.RESET_ALL}")
|
|
||||||
print(f"{Fore.RED}❌ 响应内容: {create_response.text}{Style.RESET_ALL}")
|
|
||||||
|
|
||||||
# 如果是域名问题,尝试下一个域名
|
|
||||||
if len(filtered_domains) > 1 and ("domain" in create_response.text.lower() or "address" in create_response.text.lower()):
|
|
||||||
print(f"{Fore.YELLOW}⚠️ 尝试使用下一个可用域名...{Style.RESET_ALL}")
|
|
||||||
# 将当前域名添加到屏蔽列表
|
|
||||||
if selected_domain not in self.blocked_domains:
|
|
||||||
self.blocked_domains.append(selected_domain)
|
|
||||||
# 递归调用自己
|
|
||||||
return self.create_email()
|
|
||||||
|
|
||||||
raise Exception(f"{self.translator.get('email.failed_to_create_account') if self.translator else '创建账户失败'}")
|
|
||||||
except Exception as e:
|
|
||||||
print(f"{Fore.RED}❌ 创建账户时出错: {str(e)}{Style.RESET_ALL}")
|
|
||||||
raise
|
|
||||||
|
|
||||||
# 获取访问令牌
|
|
||||||
try:
|
|
||||||
token_data = {
|
|
||||||
"address": email,
|
|
||||||
"password": password
|
|
||||||
}
|
|
||||||
|
|
||||||
token_response = requests.post(f"{self.api_url}/token", json=token_data, timeout=10)
|
|
||||||
if token_response.status_code != 200:
|
|
||||||
print(f"{Fore.RED}❌ 获取令牌失败: 状态码 {token_response.status_code}{Style.RESET_ALL}")
|
|
||||||
print(f"{Fore.RED}❌ 响应内容: {token_response.text}{Style.RESET_ALL}")
|
|
||||||
raise Exception(f"{self.translator.get('email.failed_to_get_access_token') if self.translator else '获取访问令牌失败'}")
|
|
||||||
|
|
||||||
self.token = token_response.json()["token"]
|
|
||||||
self.email = email
|
|
||||||
except Exception as e:
|
|
||||||
print(f"{Fore.RED}❌ 获取令牌时出错: {str(e)}{Style.RESET_ALL}")
|
|
||||||
raise
|
|
||||||
|
|
||||||
if self.translator:
|
|
||||||
print(f"{Fore.GREEN}✅ {self.translator.get('email.create_success')}: {email}{Style.RESET_ALL}")
|
|
||||||
else:
|
|
||||||
print(f"{Fore.GREEN}✅ 创建邮箱成功: {email}{Style.RESET_ALL}")
|
|
||||||
return email
|
|
||||||
|
|
||||||
except Exception as e:
|
|
||||||
if self.translator:
|
|
||||||
print(f"{Fore.RED}❌ {self.translator.get('email.create_error')}: {str(e)}{Style.RESET_ALL}")
|
|
||||||
else:
|
|
||||||
print(f"{Fore.RED}❌ 创建邮箱出错: {str(e)}{Style.RESET_ALL}")
|
|
||||||
return None
|
|
||||||
|
|
||||||
def close(self):
|
def close(self):
|
||||||
"""关闭浏览器"""
|
"""close browser"""
|
||||||
if self.page:
|
if self.page:
|
||||||
self.page.quit()
|
self.page.quit()
|
||||||
|
|
||||||
def refresh_inbox(self):
|
def refresh_inbox(self):
|
||||||
"""刷新邮箱"""
|
"""refresh inbox"""
|
||||||
try:
|
try:
|
||||||
if self.translator:
|
if self.translator:
|
||||||
print(f"{Fore.CYAN}🔄 {self.translator.get('email.refreshing')}{Style.RESET_ALL}")
|
print(f"{Fore.CYAN}🔄 {self.translator.get('email.refreshing')}{Style.RESET_ALL}")
|
||||||
else:
|
else:
|
||||||
print(f"{Fore.CYAN}🔄 正在刷新邮箱...{Style.RESET_ALL}")
|
print(f"{Fore.CYAN}🔄 正在刷新邮箱...{Style.RESET_ALL}")
|
||||||
|
|
||||||
# 使用 API 获取最新邮件
|
# Use API to get latest email
|
||||||
headers = {"Authorization": f"Bearer {self.token}"}
|
headers = {"Authorization": f"Bearer {self.token}"}
|
||||||
response = requests.get(f"{self.api_url}/messages", headers=headers)
|
response = requests.get(f"{self.api_url}/messages", headers=headers)
|
||||||
|
|
||||||
@@ -239,7 +265,7 @@ class NewTempEmail:
|
|||||||
def check_for_cursor_email(self):
|
def check_for_cursor_email(self):
|
||||||
"""检查是否有 Cursor 的验证邮件"""
|
"""检查是否有 Cursor 的验证邮件"""
|
||||||
try:
|
try:
|
||||||
# 使用 API 获取邮件列表
|
# Use API to get email list
|
||||||
headers = {"Authorization": f"Bearer {self.token}"}
|
headers = {"Authorization": f"Bearer {self.token}"}
|
||||||
response = requests.get(f"{self.api_url}/messages", headers=headers)
|
response = requests.get(f"{self.api_url}/messages", headers=headers)
|
||||||
|
|
||||||
@@ -247,7 +273,7 @@ class NewTempEmail:
|
|||||||
messages = response.json()["hydra:member"]
|
messages = response.json()["hydra:member"]
|
||||||
for message in messages:
|
for message in messages:
|
||||||
if message["from"]["address"] == "no-reply@cursor.sh" and "Verify your email address" in message["subject"]:
|
if message["from"]["address"] == "no-reply@cursor.sh" and "Verify your email address" in message["subject"]:
|
||||||
# 获取邮件内容
|
# Get email content
|
||||||
message_id = message["id"]
|
message_id = message["id"]
|
||||||
message_response = requests.get(f"{self.api_url}/messages/{message_id}", headers=headers)
|
message_response = requests.get(f"{self.api_url}/messages/{message_id}", headers=headers)
|
||||||
if message_response.status_code == 200:
|
if message_response.status_code == 200:
|
||||||
@@ -271,9 +297,9 @@ class NewTempEmail:
|
|||||||
return False
|
return False
|
||||||
|
|
||||||
def get_verification_code(self):
|
def get_verification_code(self):
|
||||||
"""获取验证码"""
|
"""get verification code"""
|
||||||
try:
|
try:
|
||||||
# 使用 API 获取邮件列表
|
# Use API to get email list
|
||||||
headers = {"Authorization": f"Bearer {self.token}"}
|
headers = {"Authorization": f"Bearer {self.token}"}
|
||||||
response = requests.get(f"{self.api_url}/messages", headers=headers)
|
response = requests.get(f"{self.api_url}/messages", headers=headers)
|
||||||
|
|
||||||
@@ -281,14 +307,14 @@ class NewTempEmail:
|
|||||||
messages = response.json()["hydra:member"]
|
messages = response.json()["hydra:member"]
|
||||||
for message in messages:
|
for message in messages:
|
||||||
if message["from"]["address"] == "no-reply@cursor.sh" and "Verify your email address" in message["subject"]:
|
if message["from"]["address"] == "no-reply@cursor.sh" and "Verify your email address" in message["subject"]:
|
||||||
# 获取邮件内容
|
# Get email content
|
||||||
message_id = message["id"]
|
message_id = message["id"]
|
||||||
message_response = requests.get(f"{self.api_url}/messages/{message_id}", headers=headers)
|
message_response = requests.get(f"{self.api_url}/messages/{message_id}", headers=headers)
|
||||||
|
|
||||||
if message_response.status_code == 200:
|
if message_response.status_code == 200:
|
||||||
# 从邮件内容中提取验证码
|
# Extract verification code from email content
|
||||||
email_content = message_response.json()["text"]
|
email_content = message_response.json()["text"]
|
||||||
# 查找6位数字验证码
|
# Find 6-digit verification code
|
||||||
import re
|
import re
|
||||||
code_match = re.search(r'\b\d{6}\b', email_content)
|
code_match = re.search(r'\b\d{6}\b', email_content)
|
||||||
|
|
||||||
@@ -324,7 +350,7 @@ def main(translator=None):
|
|||||||
else:
|
else:
|
||||||
print(f"\n{Fore.CYAN}📧 临时邮箱地址: {email}{Style.RESET_ALL}")
|
print(f"\n{Fore.CYAN}📧 临时邮箱地址: {email}{Style.RESET_ALL}")
|
||||||
|
|
||||||
# 测试刷新功能
|
# Test refresh function
|
||||||
while True:
|
while True:
|
||||||
if translator:
|
if translator:
|
||||||
choice = input(f"\n{translator.get('email.refresh_prompt')}: ").lower()
|
choice = input(f"\n{translator.get('email.refresh_prompt')}: ").lower()
|
||||||
|
|||||||
@@ -64,6 +64,58 @@ def get_cursor_paths(translator=None) -> Tuple[str, str]:
|
|||||||
os.path.join(base_path, paths_map[system]["main"]),
|
os.path.join(base_path, paths_map[system]["main"]),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def get_cursor_machine_id_path(translator=None) -> str:
|
||||||
|
"""
|
||||||
|
Get Cursor machineId file path based on operating system
|
||||||
|
Returns:
|
||||||
|
str: Path to machineId file
|
||||||
|
"""
|
||||||
|
if sys.platform == "win32": # Windows
|
||||||
|
return os.path.join(os.getenv("APPDATA"), "Cursor", "machineId")
|
||||||
|
elif sys.platform == "linux": # Linux
|
||||||
|
return os.path.expanduser("~/.config/Cursor/machineId")
|
||||||
|
elif sys.platform == "darwin": # macOS
|
||||||
|
return os.path.expanduser("~/Library/Application Support/Cursor/machineId")
|
||||||
|
else:
|
||||||
|
raise OSError(f"Unsupported operating system: {sys.platform}")
|
||||||
|
|
||||||
|
def get_workbench_cursor_path(translator=None) -> str:
|
||||||
|
"""Get Cursor workbench.desktop.main.js path"""
|
||||||
|
system = platform.system()
|
||||||
|
|
||||||
|
paths_map = {
|
||||||
|
"Darwin": { # macOS
|
||||||
|
"base": "/Applications/Cursor.app/Contents/Resources/app",
|
||||||
|
"main": "out/vs/workbench/workbench.desktop.main.js"
|
||||||
|
},
|
||||||
|
"Windows": {
|
||||||
|
"base": os.path.join(os.getenv("LOCALAPPDATA", ""), "Programs", "Cursor", "resources", "app"),
|
||||||
|
"main": "out/vs/workbench/workbench.desktop.main.js"
|
||||||
|
},
|
||||||
|
"Linux": {
|
||||||
|
"bases": ["/opt/Cursor/resources/app", "/usr/share/cursor/resources/app"],
|
||||||
|
"main": "out/vs/workbench/workbench.desktop.main.js"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if system not in paths_map:
|
||||||
|
raise OSError(translator.get('reset.unsupported_os', system=system) if translator else f"不支持的操作系统: {system}")
|
||||||
|
|
||||||
|
if system == "Linux":
|
||||||
|
for base in paths_map["Linux"]["bases"]:
|
||||||
|
main_path = os.path.join(base, paths_map["Linux"]["main"])
|
||||||
|
if os.path.exists(main_path):
|
||||||
|
return main_path
|
||||||
|
raise OSError(translator.get('reset.linux_path_not_found') if translator else "在 Linux 系统上未找到 Cursor 安装路径")
|
||||||
|
|
||||||
|
base_path = paths_map[system]["base"]
|
||||||
|
main_path = os.path.join(base_path, paths_map[system]["main"])
|
||||||
|
|
||||||
|
if not os.path.exists(main_path):
|
||||||
|
raise OSError(translator.get('reset.file_not_found', path=main_path) if translator else f"未找到 Cursor main.js 文件: {main_path}")
|
||||||
|
|
||||||
|
return main_path
|
||||||
|
|
||||||
def version_check(version: str, min_version: str = "", max_version: str = "", translator=None) -> bool:
|
def version_check(version: str, min_version: str = "", max_version: str = "", translator=None) -> bool:
|
||||||
"""Version number check"""
|
"""Version number check"""
|
||||||
version_pattern = r"^\d+\.\d+\.\d+$"
|
version_pattern = r"^\d+\.\d+\.\d+$"
|
||||||
@@ -102,6 +154,77 @@ def check_cursor_version(translator) -> bool:
|
|||||||
print(f"{Fore.RED}{EMOJI['ERROR']} {translator.get('reset.check_version_failed', error=str(e))}{Style.RESET_ALL}")
|
print(f"{Fore.RED}{EMOJI['ERROR']} {translator.get('reset.check_version_failed', error=str(e))}{Style.RESET_ALL}")
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
def modify_workbench_js(file_path: str, translator=None) -> bool:
|
||||||
|
"""
|
||||||
|
Modify file content
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
# Save original file permissions
|
||||||
|
original_stat = os.stat(file_path)
|
||||||
|
original_mode = original_stat.st_mode
|
||||||
|
original_uid = original_stat.st_uid
|
||||||
|
original_gid = original_stat.st_gid
|
||||||
|
|
||||||
|
# Create temporary file
|
||||||
|
with tempfile.NamedTemporaryFile(mode="w", encoding="utf-8", errors="ignore", delete=False) as tmp_file:
|
||||||
|
# Read original content
|
||||||
|
with open(file_path, "r", encoding="utf-8", errors="ignore") as main_file:
|
||||||
|
content = main_file.read()
|
||||||
|
|
||||||
|
if sys.platform == "win32":
|
||||||
|
# Define replacement patterns
|
||||||
|
CButton_old_pattern = r'$(k,E(Ks,{title:"Upgrade to Pro",size:"small",get codicon(){return F.rocket},get onClick(){return t.pay}}),null)'
|
||||||
|
CButton_new_pattern = r'$(k,E(Ks,{title:"yeongpin GitHub",size:"small",get codicon(){return F.rocket},get onClick(){return function(){window.open("https://github.com/yeongpin/cursor-free-vip","_blank")}}}),null)'
|
||||||
|
elif sys.platform == "linux":
|
||||||
|
CButton_old_pattern = r'$(k,E(Ks,{title:"Upgrade to Pro",size:"small",get codicon(){return F.rocket},get onClick(){return t.pay}}),null)'
|
||||||
|
CButton_new_pattern = r'$(k,E(Ks,{title:"yeongpin GitHub",size:"small",get codicon(){return F.rocket},get onClick(){return function(){window.open("https://github.com/yeongpin/cursor-free-vip","_blank")}}}),null)'
|
||||||
|
elif sys.platform == "darwin":
|
||||||
|
CButton_old_pattern = r'M(x,I(as,{title:"Upgrade to Pro",size:"small",get codicon(){return $.rocket},get onClick(){return t.pay}}),null)'
|
||||||
|
CButton_new_pattern = r'M(x,I(as,{title:"yeongpin GitHub",size:"small",get codicon(){return $.rocket},get onClick(){return function(){window.open("https://github.com/yeongpin/cursor-free-vip","_blank")}}}),null)'
|
||||||
|
|
||||||
|
CBadge_old_pattern = r'<div>Pro Trial'
|
||||||
|
CBadge_new_pattern = r'<div>Pro'
|
||||||
|
|
||||||
|
CToast_old_pattern = r'notifications-toasts'
|
||||||
|
CToast_new_pattern = r'notifications-toasts hidden'
|
||||||
|
|
||||||
|
# Replace content
|
||||||
|
content = content.replace(CButton_old_pattern, CButton_new_pattern)
|
||||||
|
content = content.replace(CBadge_old_pattern, CBadge_new_pattern)
|
||||||
|
content = content.replace(CToast_old_pattern, CToast_new_pattern)
|
||||||
|
|
||||||
|
# Write to temporary file
|
||||||
|
tmp_file.write(content)
|
||||||
|
tmp_path = tmp_file.name
|
||||||
|
|
||||||
|
# Backup original file
|
||||||
|
backup_path = file_path + ".backup"
|
||||||
|
if os.path.exists(backup_path):
|
||||||
|
os.remove(backup_path)
|
||||||
|
shutil.copy2(file_path, backup_path)
|
||||||
|
|
||||||
|
# Move temporary file to original position
|
||||||
|
if os.path.exists(file_path):
|
||||||
|
os.remove(file_path)
|
||||||
|
shutil.move(tmp_path, file_path)
|
||||||
|
|
||||||
|
# Restore original permissions
|
||||||
|
os.chmod(file_path, original_mode)
|
||||||
|
if os.name != "nt": # Not Windows
|
||||||
|
os.chown(file_path, original_uid, original_gid)
|
||||||
|
|
||||||
|
print(f"{Fore.GREEN}{EMOJI['SUCCESS']} {translator.get('reset.file_modified')}{Style.RESET_ALL}")
|
||||||
|
return True
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
print(f"{Fore.RED}{EMOJI['ERROR']} {translator.get('reset.modify_file_failed', error=str(e))}{Style.RESET_ALL}")
|
||||||
|
if "tmp_path" in locals():
|
||||||
|
try:
|
||||||
|
os.unlink(tmp_path)
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
return False
|
||||||
|
|
||||||
def modify_main_js(main_path: str, translator) -> bool:
|
def modify_main_js(main_path: str, translator) -> bool:
|
||||||
"""Modify main.js file"""
|
"""Modify main.js file"""
|
||||||
try:
|
try:
|
||||||
@@ -214,11 +337,20 @@ class MachineIDResetter:
|
|||||||
"~/Library/Application Support/Cursor/User/globalStorage/state.vscdb"
|
"~/Library/Application Support/Cursor/User/globalStorage/state.vscdb"
|
||||||
))
|
))
|
||||||
elif sys.platform == "linux": # Linux
|
elif sys.platform == "linux": # Linux
|
||||||
self.db_path = os.path.abspath(os.path.expanduser(
|
# 获取实际用户的主目录
|
||||||
"~/.config/Cursor/User/globalStorage/storage.json"
|
sudo_user = os.environ.get('SUDO_USER')
|
||||||
|
if sudo_user:
|
||||||
|
actual_home = f"/home/{sudo_user}"
|
||||||
|
else:
|
||||||
|
actual_home = os.path.expanduser("~")
|
||||||
|
|
||||||
|
self.db_path = os.path.abspath(os.path.join(
|
||||||
|
actual_home,
|
||||||
|
".config/Cursor/User/globalStorage/storage.json"
|
||||||
))
|
))
|
||||||
self.sqlite_path = os.path.abspath(os.path.expanduser(
|
self.sqlite_path = os.path.abspath(os.path.join(
|
||||||
"~/.config/Cursor/User/globalStorage/state.vscdb"
|
actual_home,
|
||||||
|
".config/Cursor/User/globalStorage/state.vscdb"
|
||||||
))
|
))
|
||||||
else:
|
else:
|
||||||
raise NotImplementedError(f"Not Supported OS: {sys.platform}")
|
raise NotImplementedError(f"Not Supported OS: {sys.platform}")
|
||||||
@@ -237,6 +369,8 @@ class MachineIDResetter:
|
|||||||
# Generate new sqmId
|
# Generate new sqmId
|
||||||
sqm_id = "{" + str(uuid.uuid4()).upper() + "}"
|
sqm_id = "{" + str(uuid.uuid4()).upper() + "}"
|
||||||
|
|
||||||
|
self.update_machine_id_file(dev_device_id)
|
||||||
|
|
||||||
return {
|
return {
|
||||||
"telemetry.devDeviceId": dev_device_id,
|
"telemetry.devDeviceId": dev_device_id,
|
||||||
"telemetry.macMachineId": mac_machine_id,
|
"telemetry.macMachineId": mac_machine_id,
|
||||||
@@ -309,12 +443,12 @@ class MachineIDResetter:
|
|||||||
new_guid = str(uuid.uuid4())
|
new_guid = str(uuid.uuid4())
|
||||||
winreg.SetValueEx(key, "MachineGuid", 0, winreg.REG_SZ, new_guid)
|
winreg.SetValueEx(key, "MachineGuid", 0, winreg.REG_SZ, new_guid)
|
||||||
winreg.CloseKey(key)
|
winreg.CloseKey(key)
|
||||||
print("Windows MachineGuid updated successfully")
|
print(f"{Fore.GREEN}{EMOJI['SUCCESS']} {self.translator.get('reset.windows_machine_guid_updated')}{Style.RESET_ALL}")
|
||||||
except PermissionError:
|
except PermissionError:
|
||||||
print("Permission denied: Run as administrator to update Windows MachineGuid")
|
print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('reset.permission_denied')}{Style.RESET_ALL}")
|
||||||
raise
|
raise
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f"Failed to update Windows MachineGuid: {e}")
|
print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('reset.update_windows_machine_guid_failed', error=str(e))}{Style.RESET_ALL}")
|
||||||
raise
|
raise
|
||||||
|
|
||||||
def _update_macos_platform_uuid(self, new_ids):
|
def _update_macos_platform_uuid(self, new_ids):
|
||||||
@@ -326,11 +460,11 @@ class MachineIDResetter:
|
|||||||
cmd = f'sudo plutil -replace "UUID" -string "{new_ids["telemetry.macMachineId"]}" "{uuid_file}"'
|
cmd = f'sudo plutil -replace "UUID" -string "{new_ids["telemetry.macMachineId"]}" "{uuid_file}"'
|
||||||
result = os.system(cmd)
|
result = os.system(cmd)
|
||||||
if result == 0:
|
if result == 0:
|
||||||
print("macOS Platform UUID updated successfully")
|
print(f"{Fore.GREEN}{EMOJI['SUCCESS']} {self.translator.get('reset.macos_platform_uuid_updated')}{Style.RESET_ALL}")
|
||||||
else:
|
else:
|
||||||
raise Exception("Failed to execute plutil command")
|
raise Exception(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('reset.failed_to_execute_plutil_command')}{Style.RESET_ALL}")
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f"Failed to update macOS Platform UUID: {e}")
|
print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('reset.update_macos_platform_uuid_failed', error=str(e))}{Style.RESET_ALL}")
|
||||||
raise
|
raise
|
||||||
|
|
||||||
def reset_machine_ids(self):
|
def reset_machine_ids(self):
|
||||||
@@ -373,6 +507,10 @@ class MachineIDResetter:
|
|||||||
# Update system IDs
|
# Update system IDs
|
||||||
self.update_system_ids(new_ids)
|
self.update_system_ids(new_ids)
|
||||||
|
|
||||||
|
# Modify workbench.desktop.main.js
|
||||||
|
workbench_path = get_workbench_cursor_path(self.translator)
|
||||||
|
modify_workbench_js(workbench_path, self.translator)
|
||||||
|
|
||||||
# Check Cursor version and perform corresponding actions
|
# Check Cursor version and perform corresponding actions
|
||||||
greater_than_0_45 = check_cursor_version(self.translator)
|
greater_than_0_45 = check_cursor_version(self.translator)
|
||||||
if greater_than_0_45:
|
if greater_than_0_45:
|
||||||
@@ -396,6 +534,44 @@ class MachineIDResetter:
|
|||||||
print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('reset.process_error', error=str(e))}{Style.RESET_ALL}")
|
print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('reset.process_error', error=str(e))}{Style.RESET_ALL}")
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
def update_machine_id_file(self, machine_id: str) -> bool:
|
||||||
|
"""
|
||||||
|
Update machineId file with new machine_id
|
||||||
|
Args:
|
||||||
|
machine_id (str): New machine ID to write
|
||||||
|
Returns:
|
||||||
|
bool: True if successful, False otherwise
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
# Get the machineId file path
|
||||||
|
machine_id_path = get_cursor_machine_id_path()
|
||||||
|
|
||||||
|
# Create directory if it doesn't exist
|
||||||
|
os.makedirs(os.path.dirname(machine_id_path), exist_ok=True)
|
||||||
|
|
||||||
|
# Create backup if file exists
|
||||||
|
if os.path.exists(machine_id_path):
|
||||||
|
backup_path = machine_id_path + ".backup"
|
||||||
|
try:
|
||||||
|
shutil.copy2(machine_id_path, backup_path)
|
||||||
|
print(f"{Fore.GREEN}{EMOJI['INFO']} {self.translator.get('reset.backup_created', path=backup_path) if self.translator else f'Backup created at: {backup_path}'}{Style.RESET_ALL}")
|
||||||
|
except Exception as e:
|
||||||
|
print(f"{Fore.YELLOW}{EMOJI['INFO']} {self.translator.get('reset.backup_creation_failed', error=str(e)) if self.translator else f'Could not create backup: {str(e)}'}{Style.RESET_ALL}")
|
||||||
|
|
||||||
|
# Write new machine ID to file
|
||||||
|
with open(machine_id_path, "w", encoding="utf-8") as f:
|
||||||
|
f.write(machine_id)
|
||||||
|
|
||||||
|
print(f"{Fore.GREEN}{EMOJI['SUCCESS']} {self.translator.get('reset.update_success') if self.translator else 'Successfully updated machineId file'}{Style.RESET_ALL}")
|
||||||
|
return True
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
error_msg = f"Failed to update machineId file: {str(e)}"
|
||||||
|
if self.translator:
|
||||||
|
error_msg = self.translator.get('reset.update_failed', error=str(e))
|
||||||
|
print(f"{Fore.RED}{EMOJI['ERROR']} {error_msg}{Style.RESET_ALL}")
|
||||||
|
return False
|
||||||
|
|
||||||
def run(translator=None):
|
def run(translator=None):
|
||||||
"""Convenient function for directly calling the reset function"""
|
"""Convenient function for directly calling the reset function"""
|
||||||
print(f"\n{Fore.CYAN}{'='*50}{Style.RESET_ALL}")
|
print(f"\n{Fore.CYAN}{'='*50}{Style.RESET_ALL}")
|
||||||
|
|||||||
Reference in New Issue
Block a user