forked from mirrors/cursor-free-vip
Compare commits
33 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
637f923c16 | ||
|
|
1cc93ffc22 | ||
|
|
887239d80c | ||
|
|
5d944fa3b1 | ||
|
|
654157b371 | ||
|
|
f4314cc6da | ||
|
|
1f29b2dbbe | ||
|
|
9c2b3f2fc8 | ||
|
|
8e20a0ed3d | ||
|
|
4122701468 | ||
|
|
1ee9813155 | ||
|
|
a9e4b3a5c6 | ||
|
|
a83851d441 | ||
|
|
1e290d0417 | ||
|
|
53ab15604e | ||
|
|
638916e5ef | ||
|
|
9500ce1249 | ||
|
|
721c13cb2f | ||
|
|
a04eed2c6b | ||
|
|
8107bede63 | ||
|
|
4166bc5135 | ||
|
|
69994d2486 | ||
|
|
ffcb8ec140 | ||
|
|
b61b61c607 | ||
|
|
7326d0eeb0 | ||
|
|
371f00645d | ||
|
|
a873291481 | ||
|
|
7710ea4bb3 | ||
|
|
13483eed77 | ||
|
|
eb69f933af | ||
|
|
54cd8cf323 | ||
|
|
4e0289c86c | ||
|
|
af4a1c4065 |
206
.github/workflows/build.yml
vendored
Normal file
206
.github/workflows/build.yml
vendored
Normal file
@@ -0,0 +1,206 @@
|
||||
name: Build Executables
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
version:
|
||||
description: 'Version number (e.g. 1.0.9)'
|
||||
required: true
|
||||
default: '1.0.9-dev'
|
||||
|
||||
permissions:
|
||||
contents: write
|
||||
actions: write
|
||||
packages: write
|
||||
|
||||
jobs:
|
||||
create-tag:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
with:
|
||||
fetch-depth: 0 # 获取所有标签
|
||||
|
||||
- name: Delete existing tag if exists
|
||||
run: |
|
||||
if git ls-remote --tags origin | grep -q "refs/tags/v${{ github.event.inputs.version }}"; then
|
||||
git push origin --delete "v${{ github.event.inputs.version }}" || true
|
||||
git tag -d "v${{ github.event.inputs.version }}" || true
|
||||
fi
|
||||
|
||||
- name: Create Tag
|
||||
run: |
|
||||
git tag "v${{ github.event.inputs.version }}"
|
||||
git push origin "v${{ github.event.inputs.version }}"
|
||||
|
||||
build-windows:
|
||||
needs: create-tag
|
||||
runs-on: windows-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@v2
|
||||
with:
|
||||
python-version: '3.x'
|
||||
|
||||
- name: Set version
|
||||
shell: bash
|
||||
run: echo "VERSION=${{ github.event.inputs.version }}" >> $GITHUB_ENV
|
||||
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
python -m pip install --upgrade pip
|
||||
pip install pyinstaller
|
||||
pip install -r requirements.txt
|
||||
|
||||
- name: Build EXE
|
||||
run: |
|
||||
pyinstaller build.spec
|
||||
|
||||
- name: Upload Windows artifact
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: CursorFreeVIP_${{ env.VERSION }}_windows.exe
|
||||
path: dist/*
|
||||
|
||||
build-macos-arm64:
|
||||
needs: create-tag
|
||||
runs-on: macos-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@v2
|
||||
with:
|
||||
python-version: '3.x'
|
||||
|
||||
- name: Set version
|
||||
shell: bash
|
||||
run: echo "VERSION=${{ github.event.inputs.version }}" >> $GITHUB_ENV
|
||||
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
python -m pip install --upgrade pip
|
||||
pip install pyinstaller
|
||||
pip install -r requirements.txt
|
||||
|
||||
- name: Build MacOS ARM executable
|
||||
run: |
|
||||
pyinstaller build.spec
|
||||
|
||||
- name: Upload MacOS ARM artifact
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: CursorFreeVIP_${{ env.VERSION }}_mac_arm64
|
||||
path: dist/*
|
||||
|
||||
build-linux:
|
||||
needs: create-tag
|
||||
runs-on: ubuntu-22.04
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@v2
|
||||
with:
|
||||
python-version: '3.x'
|
||||
|
||||
- name: Set version
|
||||
shell: bash
|
||||
run: echo "VERSION=${{ github.event.inputs.version }}" >> $GITHUB_ENV
|
||||
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
python -m pip install --upgrade pip
|
||||
pip install pyinstaller
|
||||
pip install -r requirements.txt
|
||||
|
||||
- name: Build Linux executable
|
||||
run: |
|
||||
pyinstaller build.spec
|
||||
|
||||
- name: Upload Linux artifact
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: CursorFreeVIP_${{ env.VERSION }}_linux
|
||||
path: dist/*
|
||||
|
||||
|
||||
build-macos-intel:
|
||||
needs: create-tag
|
||||
runs-on: macos-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@v2
|
||||
with:
|
||||
python-version: '3.x'
|
||||
|
||||
- name: Set version
|
||||
shell: bash
|
||||
run: echo "VERSION=${{ github.event.inputs.version }}" >> $GITHUB_ENV
|
||||
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
arch -x86_64 pip3 install --upgrade pip
|
||||
arch -x86_64 pip3 install pyinstaller
|
||||
arch -x86_64 pip3 install -r requirements.txt
|
||||
|
||||
- name: Build MacOS Intel executable
|
||||
env:
|
||||
TARGET_ARCH: 'x86_64'
|
||||
run: |
|
||||
arch -x86_64 python3 -m PyInstaller build.spec
|
||||
|
||||
- name: Upload MacOS Intel artifact
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: CursorFreeVIP_${{ env.VERSION }}_mac_intel
|
||||
path: dist/*
|
||||
|
||||
|
||||
create-release:
|
||||
needs: [build-windows, build-macos-arm64, build-linux, build-macos-intel]
|
||||
runs-on: ubuntu-22.04
|
||||
|
||||
steps:
|
||||
- name: Get version
|
||||
shell: bash
|
||||
run: echo "VERSION=${{ github.event.inputs.version }}" >> $GITHUB_ENV
|
||||
|
||||
- name: Download all artifacts
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
path: artifacts
|
||||
|
||||
- name: Prepare release files
|
||||
run: |
|
||||
cd artifacts
|
||||
# 重命名文件为最终的可执行文件名
|
||||
mv CursorFreeVIP_${{ env.VERSION }}_windows.exe/CursorFreeVIP.exe CursorFreeVIP_${{ env.VERSION }}_windows.exe
|
||||
mv CursorFreeVIP_${{ env.VERSION }}_mac_arm64/CursorFreeVIP CursorFreeVIP_${{ env.VERSION }}_mac_arm64
|
||||
mv CursorFreeVIP_${{ env.VERSION }}_linux/CursorFreeVIP CursorFreeVIP_${{ env.VERSION }}_linux
|
||||
mv CursorFreeVIP_${{ env.VERSION }}_mac_intel/CursorFreeVIP CursorFreeVIP_${{ env.VERSION }}_mac_intel
|
||||
# 删除空目录
|
||||
rm -rf */
|
||||
ls -la
|
||||
|
||||
- name: Create Release
|
||||
uses: softprops/action-gh-release@v1
|
||||
with:
|
||||
tag_name: v${{ env.VERSION }}
|
||||
files: |
|
||||
artifacts/CursorFreeVIP_${{ env.VERSION }}_windows.exe
|
||||
artifacts/CursorFreeVIP_${{ env.VERSION }}_mac_arm64
|
||||
artifacts/CursorFreeVIP_${{ env.VERSION }}_linux
|
||||
artifacts/CursorFreeVIP_${{ env.VERSION }}_mac_intel
|
||||
draft: false
|
||||
prerelease: false
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
145
CHANGELOG.md
Normal file
145
CHANGELOG.md
Normal file
@@ -0,0 +1,145 @@
|
||||
# Change Log
|
||||
|
||||
|
||||
## v1.2.01
|
||||
|
||||
1. Fix Cursor Cloudflare Human Verification Problem | 修復Cursor Cloudflare人機驗證問題
|
||||
2. Change to automatic registration account | 全面改為自動註冊賬號
|
||||
3. Change Mail Site | 改變郵箱網站
|
||||
4. Fix Cursor Cloudflare Problem | 修復Cursor Cloudflare問題
|
||||
|
||||
|
||||
## v1.1.01
|
||||
|
||||
<p align="center">
|
||||
<img src="./images/cloudflare_2025-02-12_13-43-21.png" alt="free" width="400"/><br>
|
||||
</p>
|
||||
|
||||
1. Hot Fix Cursor Cloudflare Problem | 修復Cursor Cloudflare問題
|
||||
2. Fix Cursor Cloudflare Human Verification Problem | 修復Cursor Cloudflare人機驗證問題
|
||||
3. Remake signup logic | 重做註冊邏輯
|
||||
|
||||
|
||||
## v1.0.10
|
||||
|
||||
1. Hot Fix Mac Chrome Problem | 修復Mac Chrome問題
|
||||
2. Fix Linux Start Donet Problem | 修復Linux啟動開發者問題
|
||||
|
||||
|
||||
## v1.0.9
|
||||
|
||||
<p align="center">
|
||||
<img src="./images/cloudflare_2025-02-12_13-43-21.png" alt="free" width="400"/><br>
|
||||
</p>
|
||||
|
||||
1. Fixed New 0.45.x Version Reset Machine | 修復新0.45版本重置機器
|
||||
2. Fix Locale Language | 修復多語言
|
||||
3. Add Support Crypto Machine Regedit | 增加支持加密機器註冊
|
||||
4. Add Remake main.js | 重做main.js
|
||||
|
||||
|
||||
## v1.0.8
|
||||
|
||||
1. Fix New 0.45 Version Reset Machine | 修復新0.45版本重置機器
|
||||
2. Fix Locale Language | 修復多語言
|
||||
3. Add Support Crypto Machine Regedit | 增加支持加密機器註冊
|
||||
|
||||
|
||||
## v1.0.7 - HotFix
|
||||
|
||||
1. Fix Reset Machine | 修復重置機器
|
||||
2. Fix Locale Language | 修復多語言
|
||||
|
||||
|
||||
## v1.0.7
|
||||
|
||||
1. Add Locale Language Support | 增加多語言支持
|
||||
<p align="center">
|
||||
<img src="./images/locale_2025-01-15_13-40-08.png" alt="locale" width="400"/><br>
|
||||
</p>
|
||||
|
||||
|
||||
## v1.0.6
|
||||
|
||||
1. Add Quit Cursor Option | 增加退出Cursor選項
|
||||
2. Add Recaptcha Path Patch | 增加Recaptcha路徑修復
|
||||
3. Fix Admin Permission | 修復管理員權限問題
|
||||
4. Remove all need admin permission | 移除所有需要管理員權限
|
||||
|
||||
|
||||
## v1.0.5 - HotFix
|
||||
|
||||
1. Fix: Mac Browser Control | 修復Mac瀏覽器控制問題
|
||||
2. Fix: Verification Code Cant Patch | 修復驗證碼無法修復問題
|
||||
3. Add Linux Support | 增加Linux支持
|
||||
<p align="center">
|
||||
<img src="./images/fix_2025-01-14_21-30-43.png" alt="fix" width="400"/><br>
|
||||
</p>
|
||||
|
||||
|
||||
## v1.0.5
|
||||
|
||||
1. Remove MachineID | 移除機器碼ID
|
||||
2. Change to automatic registration account | 全面改為自動註冊賬號
|
||||
3. Use your own exclusive new account | 使用自己獨享的新賬號
|
||||
4. Fully automatic reset machine configuration | 全面自動化重置機器配置
|
||||
<p align="center">
|
||||
<img src="./images/pro_2025-01-14_14-40-37.png" alt="Why" width="400"/><br>
|
||||
</p>
|
||||
|
||||
|
||||
## v1.0.4
|
||||
|
||||
1. Fix: Cursor's configuration | 修復Cursor的配置問題
|
||||
2. Fix Cloud Lame | 修復雲端慢速模式
|
||||
|
||||
|
||||
## v1.0.3
|
||||
|
||||
1. Fix: Cursor's configuration | 修復Cursor的配置問題
|
||||
2. Add Manual Reset Machine | 增加手動重置機器
|
||||
3. Add CDN Cloud Control WatchDog | 增加CDN雲端控制WatchDog
|
||||
4. Add Mac OS Support | 增加Mac OS支持
|
||||
5. 759 ++ People use , but star only a few | 759 ++人使用,但只有幾個人點贊
|
||||
<p align="center">
|
||||
<img src="./images/what_2025-01-13_13-32-54.png" alt="Why" width="400"/><br>
|
||||
</p>
|
||||
|
||||
|
||||
## v1.0.2
|
||||
|
||||
1. Fix: Some known issues | 修復了一些已知問題
|
||||
2. Add cloud control device code | 增加雲端控制設備碼
|
||||
3. Cloud reset device code | 雲端重置設備碼
|
||||
4. Remove official WatchDog monitoring | 移除官方WatchDog監控
|
||||
5. Remove Proxy official prompt | 移除Proxy 官方提示
|
||||
6. Fix: Too Many Computer | 修復Too Many Computer 問題
|
||||
7. Fix Billing Issue | 修復計費問題
|
||||
8. Fix: Cursor's configuration | 修復Cursor的配置問題
|
||||
9. Fix cursor-slow mode | 修復cursor-slow模式
|
||||
|
||||
|
||||
## v1.0.1
|
||||
|
||||
1. Fix: Reset machine ID | 修復了重置機器ID的問題
|
||||
2. Fix: Bypass membership check | 修復了 繞過會員檢查的問題
|
||||
3. Fix: Auto upgrade to "pro" membership | 修復了 自動升級為pro會員的問題
|
||||
4. Fix: Real-time send Token request | 修復了 實時發送Token請求的問題
|
||||
5. Fix: Reset Cursor's configuration | 修復了 重置Cursor的配置的問題
|
||||
|
||||
|
||||
|
||||
## v1.0
|
||||
1. Preview Image | 預覽圖<br>
|
||||
<p align="center">
|
||||
<img src="./images/pro_2025-01-11_00-50-40.png" alt="Cursor Pro Logo" width="400"/><br>
|
||||
</p>
|
||||
<p align="center">
|
||||
<img src="./images/pro_2025-01-11_00-51-07.png" alt="Cursor Pro Logo" width="400"/><br>
|
||||
</p>
|
||||
2. Add usage period,but can be contacted by leaving MachineID | 不得已才添加,但可以通過留下MachineID 聯繫作者
|
||||
<br>
|
||||
|
||||
<p align="center">
|
||||
<img src="./images/pro_2025-01-11_16-24-03.png" alt="Cursor Pro Logo" width="400"/><br>
|
||||
</p>
|
||||
121
README.md
121
README.md
@@ -11,132 +11,31 @@
|
||||
[](https://github.com/yeongpin/cursor-free-vip/stargazers)
|
||||
|
||||
</p>
|
||||
<h4>Support Latest 0.45.11 Version | 支持最新0.45.11版本</h4>
|
||||
|
||||
This is a tool to automatically register (except for Google verification code), 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.
|
||||
|
||||
這是一個自動化工具,自動註冊(除了Google驗證碼),支持 Windows 和 macOS 系統,完成Auth驗證,重置Cursor的配置。
|
||||
|
||||
<p align="center">
|
||||
<img src="./images/pro_2025-01-14_14-40-37.png" alt="new" width="400"/><br>
|
||||
<img src="./images/new107_2025-01-15_13-53-56.png" alt="new" width="400"/><br>
|
||||
</p>
|
||||
|
||||
<br>
|
||||
<p align="center">
|
||||
<img src="./images/free_2025-01-14_14-59-15.png" alt="free" width="400"/><br>
|
||||
</p>
|
||||
##### If you dont have google chrome , you can download it from [here](https://www.google.com/intl/en_pk/chrome/)
|
||||
|
||||
## ⚠️ Google Recaptcha need to be manually verified, don't be lazy, move your fingers, verify it, otherwise it will keep prompting you to verify ⚠️
|
||||
### If you dont have google chrome , you can download it from [here](https://www.google.com/intl/en_pk/chrome/)
|
||||
|
||||
## ⚠️ 郵箱驗證 需要手動驗證,不要那麼懶,動一動手指,驗證一下,不然會一直提示你驗證 ⚠️
|
||||
### 如果沒有Google Chrome,可以從[這裡](https://www.google.com/intl/en_pk/chrome/)下載
|
||||
##### 如果沒有Google Chrome,可以從[這裡](https://www.google.com/intl/en_pk/chrome/)下載
|
||||
|
||||
</p>
|
||||
</div>
|
||||
|
||||
|
||||
## 🔄 更新日志
|
||||
<details open>
|
||||
<summary>v1.0.7</summary>
|
||||
|
||||
1. Add Locale Language Support | 增加多語言支持
|
||||
<p align="center">
|
||||
<img src="./images/locale_2025-01-15_13-40-08.png" alt="locale" width="400"/><br>
|
||||
</p>
|
||||
</details>
|
||||
<details>
|
||||
<summary>v1.0.6</summary>
|
||||
|
||||
1. Add Quit Cursor Option | 增加退出Cursor選項
|
||||
2. Add Recaptcha Path Patch | 增加Recaptcha路徑修復
|
||||
3. Fix Admin Permission | 修復管理員權限問題
|
||||
4. Remove all need admin permission | 移除所有需要管理員權限
|
||||
</details>
|
||||
<details>
|
||||
<summary>v1.0.5 - HotFix</summary>
|
||||
|
||||
1. Fix: Mac Browser Control | 修復Mac瀏覽器控制問題
|
||||
2. Fix: Verification Code Cant Patch | 修復驗證碼無法修復問題
|
||||
3. Add Linux Support | 增加Linux支持
|
||||
<p align="center">
|
||||
<img src="./images/fix_2025-01-14_21-30-43.png" alt="fix" width="400"/><br>
|
||||
</p>
|
||||
</details>
|
||||
<details>
|
||||
<summary>v1.0.5</summary>
|
||||
|
||||
1. Remove MachineID | 移除機器碼ID
|
||||
2. Change to automatic registration account | 全面改為自動註冊賬號
|
||||
3. Use your own exclusive new account | 使用自己獨享的新賬號
|
||||
4. Fully automatic reset machine configuration | 全面自動化重置機器配置
|
||||
<p align="center">
|
||||
<img src="./images/pro_2025-01-14_14-40-37.png" alt="Why" width="400"/><br>
|
||||
</p>
|
||||
</details>
|
||||
<details>
|
||||
<summary>v1.0.4</summary>
|
||||
|
||||
1. Fix: Cursor's configuration | 修復Cursor的配置問題
|
||||
2. Fix Cloud Lame | 修復雲端慢速模式
|
||||
</details>
|
||||
<details>
|
||||
<summary>v1.0.3</summary>
|
||||
|
||||
1. Fix: Cursor's configuration | 修復Cursor的配置問題
|
||||
2. Add Manual Reset Machine | 增加手動重置機器
|
||||
3. Add CDN Cloud Control WatchDog | 增加CDN雲端控制WatchDog
|
||||
4. Add Mac OS Support | 增加Mac OS支持
|
||||
5. 759 ++ People use , but star only a few | 759 ++人使用,但只有幾個人點贊
|
||||
<p align="center">
|
||||
<img src="./images/what_2025-01-13_13-32-54.png" alt="Why" width="400"/><br>
|
||||
</p>
|
||||
</details>
|
||||
<details>
|
||||
<summary>v1.0.2</summary>
|
||||
|
||||
1. Fix: Some known issues | 修復了一些已知問題
|
||||
2. Add cloud control device code | 增加雲端控制設備碼
|
||||
3. Cloud reset device code | 雲端重置設備碼
|
||||
4. Remove official WatchDog monitoring | 移除官方WatchDog監控
|
||||
5. Remove Proxy official prompt | 移除Proxy 官方提示
|
||||
6. Fix: Too Many Computer | 修復Too Many Computer 問題
|
||||
7. Fix Billing Issue | 修復計費問題
|
||||
8. Fix: Cursor's configuration | 修復Cursor的配置問題
|
||||
9. Fix cursor-slow mode | 修復cursor-slow模式
|
||||
</details>
|
||||
<details>
|
||||
<summary>v1.0.1</summary>
|
||||
|
||||
1. Fix: Reset machine ID | 修復了重置機器ID的問題
|
||||
2. Fix: Bypass membership check | 修復了 繞過會員檢查的問題
|
||||
3. Fix: Auto upgrade to "pro" membership | 修復了 自動升級為pro會員的問題
|
||||
4. Fix: Real-time send Token request | 修復了 實時發送Token請求的問題
|
||||
5. Fix: Reset Cursor's configuration | 修復了 重置Cursor的配置的問題
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary>v1.0</summary>
|
||||
1. Preview Image | 預覽圖<br>
|
||||
<p align="center">
|
||||
<img src="./images/pro_2025-01-11_00-50-40.png" alt="Cursor Pro Logo" width="400"/><br>
|
||||
</p>
|
||||
<p align="center">
|
||||
<img src="./images/pro_2025-01-11_00-51-07.png" alt="Cursor Pro Logo" width="400"/><br>
|
||||
</p>
|
||||
2. Add usage period,but can be contacted by leaving MachineID | 不得已才添加,但可以通過留下MachineID 聯繫作者
|
||||
<br>
|
||||
|
||||
<p align="center">
|
||||
<img src="./images/pro_2025-01-11_16-24-03.png" alt="Cursor Pro Logo" width="400"/><br>
|
||||
</p>
|
||||
</details>
|
||||
## 🔄 Change Log | 更新日志
|
||||
[Watch Change Log | 查看更新日志](CHANGELOG.md)
|
||||
|
||||
## ✨ Features | 功能特點
|
||||
|
||||
* Automatically register Cursor membership<br>自動註冊Cursor會員<br>
|
||||
|
||||
* Except for Google verification code<br>除了Google驗證碼<br>
|
||||
|
||||
* Support Windows and macOS systems<br>支持 Windows 和 macOS 系統<br>
|
||||
|
||||
* Complete Auth verification<br>完成Auth驗證<br>
|
||||
@@ -153,9 +52,7 @@ This is a tool to automatically register (except for Google verification code),
|
||||
|Linux|ARM64|✅|Linux|ARM64|✅|
|
||||
|
||||
## 👀 How to use | 如何使用
|
||||
|⚠️Must logout your account before running the script⚠️|⚠️必須先登出你的帳戶再運行腳本⚠️ |
|
||||
|:---:|:---:|
|
||||
<br>
|
||||
|
||||
<details open>
|
||||
<summary><b>⭐ Auto Run Script | 腳本自動化運行</b></summary>
|
||||
|
||||
@@ -190,8 +87,6 @@ irm https://raw.githubusercontent.com/yeongpin/cursor-free-vip/main/scripts/rese
|
||||
|
||||
* Confirm that Cursor is closed before running the script <br>請確保在運行腳本前已經關閉 Cursor<br>
|
||||
|
||||
* Do not close this script when using Cursor <br>使用Cursor時請勿關閉此腳本<br>
|
||||
|
||||
* This tool is only for learning and research purposes <br>此工具僅供學習和研究使用<br>
|
||||
|
||||
* Please comply with the relevant software usage terms when using this tool <br>使用本工具時請遵守相關軟件使用條款
|
||||
|
||||
41
browser.py
41
browser.py
@@ -2,6 +2,7 @@ from DrissionPage import ChromiumOptions, ChromiumPage
|
||||
import sys
|
||||
import os
|
||||
import logging
|
||||
import random
|
||||
|
||||
|
||||
class BrowserManager:
|
||||
@@ -26,27 +27,36 @@ class BrowserManager:
|
||||
try:
|
||||
extension_path = self._get_extension_path()
|
||||
co.add_extension(extension_path)
|
||||
co.set_argument("--allow-extensions-in-incognito")
|
||||
|
||||
extension_block_path = self.get_extension_block()
|
||||
co.add_extension(extension_block_path)
|
||||
|
||||
extension_recaptcha_path = self.get_extension_recaptcha()
|
||||
co.add_extension(extension_recaptcha_path)
|
||||
|
||||
co.set_argument("--allow-extensions-in-incognito")
|
||||
except FileNotFoundError as e:
|
||||
logging.warning(f"警告: {e}")
|
||||
|
||||
# 设置更真实的用户代理
|
||||
co.set_user_agent(
|
||||
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.6723.92 Safari/537.36"
|
||||
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36"
|
||||
)
|
||||
|
||||
# 基本设置
|
||||
co.set_pref("credentials_enable_service", False)
|
||||
co.set_argument("--hide-crash-restore-bubble")
|
||||
|
||||
# 随机端口
|
||||
co.auto_port()
|
||||
|
||||
# Mac 系统特殊处理
|
||||
if sys.platform == "darwin":
|
||||
co.set_argument("--no-sandbox")
|
||||
# 系统特定设置
|
||||
if sys.platform == "darwin": # macOS
|
||||
co.set_argument("--disable-gpu")
|
||||
co.set_argument("--no-sandbox")
|
||||
elif sys.platform == "win32": # Windows
|
||||
co.set_argument("--disable-software-rasterizer")
|
||||
|
||||
# 设置窗口大小
|
||||
window_width = random.randint(1024, 1920)
|
||||
window_height = random.randint(768, 1080)
|
||||
co.set_argument(f"--window-size={window_width},{window_height}")
|
||||
|
||||
return co
|
||||
|
||||
@@ -76,19 +86,6 @@ class BrowserManager:
|
||||
|
||||
return extension_path
|
||||
|
||||
def get_extension_recaptcha(self):
|
||||
"""获取插件路径"""
|
||||
root_dir = os.getcwd()
|
||||
extension_path = os.path.join(root_dir, "recaptchaPatch")
|
||||
|
||||
if hasattr(sys, "_MEIPASS"):
|
||||
extension_path = os.path.join(sys._MEIPASS, "recaptchaPatch")
|
||||
|
||||
if not os.path.exists(extension_path):
|
||||
raise FileNotFoundError(f"插件不存在: {extension_path}")
|
||||
|
||||
return extension_path
|
||||
|
||||
def quit(self):
|
||||
"""关闭浏览器"""
|
||||
if self.browser:
|
||||
|
||||
@@ -24,14 +24,14 @@ a = Analysis(
|
||||
binaries=[],
|
||||
datas=[
|
||||
('turnstilePatch', 'turnstilePatch'),
|
||||
('recaptchaPatch', 'recaptchaPatch'),
|
||||
('uBlock0.chromium', 'uBlock0.chromium'),
|
||||
('locales', 'locales'),
|
||||
('cursor_auth.py', '.'),
|
||||
('reset_machine_manual.py', '.'),
|
||||
('cursor_register.py', '.'),
|
||||
('browser.py', '.'),
|
||||
('control.py', '.')
|
||||
('control.py', '.'),
|
||||
('.env', '.')
|
||||
],
|
||||
hiddenimports=[
|
||||
'cursor_auth',
|
||||
|
||||
136
control.py
136
control.py
@@ -58,67 +58,7 @@ class BrowserControl:
|
||||
def get_current_tab(self):
|
||||
"""获取当前标签页"""
|
||||
return self.browser
|
||||
|
||||
def generate_new_email(self):
|
||||
"""点击新的按钮生成新邮箱"""
|
||||
try:
|
||||
print(f"{Fore.CYAN}{EMOJI['MAIL']} {self.translator.get('control.generate_email')}...{Style.RESET_ALL}")
|
||||
new_button = self.browser.ele('xpath://button[contains(@class, "egenbut")]')
|
||||
if new_button:
|
||||
new_button.click()
|
||||
time.sleep(1) # 等待生成
|
||||
print(f"{Fore.GREEN}{EMOJI['SUCCESS']} {self.translator.get('control.generate_email_success')}{Style.RESET_ALL}")
|
||||
return True
|
||||
else:
|
||||
print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('control.generate_email_failed')}{Style.RESET_ALL}")
|
||||
return False
|
||||
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 select_email_domain(self, domain_index=None):
|
||||
"""选择邮箱域名,如果不指定index则随机选择"""
|
||||
try:
|
||||
print(f"{Fore.CYAN}{EMOJI['MAIL']} {self.translator.get('control.select_email_domain')}...{Style.RESET_ALL}")
|
||||
# 找到下拉框
|
||||
select_element = self.browser.ele('xpath://select[@id="seldom"]')
|
||||
if select_element:
|
||||
# 获取所有选项,包括两个 optgroup 下的所有 option
|
||||
all_options = []
|
||||
|
||||
# 获取 "新的" 组下的选项
|
||||
new_options = self.browser.eles('xpath://select[@id="seldom"]/optgroup[@label="-- 新的 --"]/option')
|
||||
all_options.extend(new_options)
|
||||
|
||||
# 获取 "其他" 组下的选项
|
||||
other_options = self.browser.eles('xpath://select[@id="seldom"]/optgroup[@label="-- 其他 --"]/option')
|
||||
all_options.extend(other_options)
|
||||
|
||||
if all_options:
|
||||
# 如果没有指定索引,随机选择一个
|
||||
if domain_index is None:
|
||||
domain_index = random.randint(0, len(all_options) - 1)
|
||||
|
||||
if domain_index < len(all_options):
|
||||
# 获取选中选项的文本
|
||||
selected_domain = all_options[domain_index].text
|
||||
print(f"{Fore.CYAN}{EMOJI['MAIL']} {self.translator.get('control.select_email_domain')}: {selected_domain}{Style.RESET_ALL}")
|
||||
|
||||
# 点击选择
|
||||
all_options[domain_index].click()
|
||||
time.sleep(1)
|
||||
print(f"{Fore.GREEN}{EMOJI['SUCCESS']} {self.translator.get('control.select_email_domain_success')}{Style.RESET_ALL}")
|
||||
return True
|
||||
|
||||
print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('control.no_available_domain_options', count=len(all_options))}{Style.RESET_ALL}")
|
||||
return False
|
||||
else:
|
||||
print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('control.no_domain_select_box')}{Style.RESET_ALL}")
|
||||
return False
|
||||
except Exception as e:
|
||||
print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('control.select_email_domain_failed', error=str(e))}{Style.RESET_ALL}")
|
||||
return False
|
||||
|
||||
|
||||
def wait_for_page_load(self, seconds=2):
|
||||
"""等待页面加载"""
|
||||
time.sleep(seconds)
|
||||
@@ -134,80 +74,6 @@ class BrowserControl:
|
||||
print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('control.browser_error', error=str(e))}{Style.RESET_ALL}")
|
||||
return False
|
||||
|
||||
def copy_and_get_email(self):
|
||||
"""获取邮箱地址"""
|
||||
try:
|
||||
print(f"{Fore.CYAN}{EMOJI['MAIL']} {self.translator.get('control.generate_email')}...{Style.RESET_ALL}")
|
||||
|
||||
# 等待元素加载
|
||||
time.sleep(1)
|
||||
|
||||
# 获取邮箱名称
|
||||
try:
|
||||
email_div = self.browser.ele('xpath://div[@class="segen"]//div[contains(@style, "color: #e5e5e5")]')
|
||||
if email_div:
|
||||
email_name = email_div.text.split()[0]
|
||||
print(f"{Fore.CYAN}{EMOJI['MAIL']} {self.translator.get('control.get_email_name')}: {email_name}{Style.RESET_ALL}")
|
||||
else:
|
||||
print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('control.get_email_name_failed')}{Style.RESET_ALL}")
|
||||
return None
|
||||
except Exception as e:
|
||||
print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('control.get_email_name_failed', error=str(e))}{Style.RESET_ALL}")
|
||||
return None
|
||||
|
||||
# 直接使用上一步选择的域名
|
||||
try:
|
||||
domain = self.browser.ele('xpath://select[@id="seldom"]').value
|
||||
if not domain: # 如果获取不到value,尝试获取选中的选项文本
|
||||
selected_option = self.browser.ele('xpath://select[@id="seldom"]/option[1]')
|
||||
domain = selected_option.text if selected_option else "@yopmail.com" # 使用默认域名作为后备
|
||||
except:
|
||||
domain = "@yopmail.com" # 如果出错,使用默认域名
|
||||
|
||||
# 组合完整邮箱地址
|
||||
full_email = f"{email_name}{domain}"
|
||||
print(f"{Fore.GREEN}{EMOJI['MAIL']} {self.translator.get('control.get_email_address')}: {full_email}{Style.RESET_ALL}")
|
||||
return full_email
|
||||
|
||||
except Exception as e:
|
||||
print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('control.get_email_address_failed', error=str(e))}{Style.RESET_ALL}")
|
||||
return None
|
||||
|
||||
def view_mailbox(self):
|
||||
"""点击查看邮箱按钮"""
|
||||
try:
|
||||
print(f"{Fore.CYAN}{EMOJI['MAIL']} {self.translator.get('control.enter_mailbox')}...{Style.RESET_ALL}")
|
||||
view_button = self.browser.ele('xpath://button[contains(@class, "egenbut") and contains(.//span, "查看邮箱")]')
|
||||
if view_button:
|
||||
view_button.click()
|
||||
time.sleep(2) # 等待页面加载
|
||||
print(f"{Fore.GREEN}{EMOJI['SUCCESS']} {self.translator.get('control.enter_mailbox_success')}{Style.RESET_ALL}")
|
||||
return True
|
||||
else:
|
||||
print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('control.no_view_mailbox_button')}{Style.RESET_ALL}")
|
||||
return False
|
||||
except Exception as e:
|
||||
print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('control.enter_mailbox_failed', error=str(e))}{Style.RESET_ALL}")
|
||||
return False
|
||||
|
||||
def refresh_mailbox(self):
|
||||
"""刷新邮箱获取最新信息"""
|
||||
try:
|
||||
print(f"{Fore.CYAN}{EMOJI['MAIL']} {self.translator.get('control.refresh_mailbox')}...{Style.RESET_ALL}")
|
||||
refresh_button = self.browser.ele('xpath://button[@id="refresh"]')
|
||||
if refresh_button:
|
||||
refresh_button.click()
|
||||
time.sleep(2) # 等待刷新完成
|
||||
print(f"{Fore.GREEN}{EMOJI['SUCCESS']} {self.translator.get('control.refresh_mailbox_success')}{Style.RESET_ALL}")
|
||||
return True
|
||||
else:
|
||||
print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('control.no_refresh_button')}{Style.RESET_ALL}")
|
||||
return False
|
||||
except Exception as e:
|
||||
print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('control.refresh_mailbox_failed', error=str(e))}{Style.RESET_ALL}")
|
||||
return False
|
||||
|
||||
|
||||
def get_verification_code(self):
|
||||
"""从邮件中获取验证码"""
|
||||
try:
|
||||
|
||||
@@ -56,7 +56,7 @@ class CursorAuth:
|
||||
|
||||
# 重新连接数据库
|
||||
conn = sqlite3.connect(self.db_path)
|
||||
print(f"{EMOJI['INFO']} {Fore.GREEN}{self.translator.get('auth.connected_to_database')}{Style.RESET_ALL}")
|
||||
print(f"{EMOJI['INFO']} {Fore.GREEN} {self.translator.get('auth.connected_to_database')}{Style.RESET_ALL}")
|
||||
cursor = conn.cursor()
|
||||
|
||||
# 增加超时和其他优化设置
|
||||
@@ -90,7 +90,7 @@ class CursorAuth:
|
||||
UPDATE ItemTable SET value = ?
|
||||
WHERE key = ?
|
||||
""", (value, key))
|
||||
print(f"{EMOJI['INFO']} {Fore.CYAN}Updating {key.split('/')[-1]}...{Style.RESET_ALL}")
|
||||
print(f"{EMOJI['INFO']} {Fore.CYAN} {self.translator.get('auth.updating_pair')} {key.split('/')[-1]}...{Style.RESET_ALL}")
|
||||
|
||||
cursor.execute("COMMIT")
|
||||
print(f"{EMOJI['SUCCESS']} {Fore.GREEN}{self.translator.get('auth.database_updated_successfully')}{Style.RESET_ALL}")
|
||||
@@ -101,14 +101,14 @@ class CursorAuth:
|
||||
raise e
|
||||
|
||||
except sqlite3.Error as e:
|
||||
print(f"\n{EMOJI['ERROR']} {Fore.RED}{self.translator.get('auth.database_error', error=str(e))}{Style.RESET_ALL}")
|
||||
print(f"\n{EMOJI['ERROR']} {Fore.RED} {self.translator.get('auth.database_error', error=str(e))}{Style.RESET_ALL}")
|
||||
return False
|
||||
except Exception as e:
|
||||
print(f"\n{EMOJI['ERROR']} {Fore.RED}{self.translator.get('auth.an_error_occurred', error=str(e))}{Style.RESET_ALL}")
|
||||
print(f"\n{EMOJI['ERROR']} {Fore.RED} {self.translator.get('auth.an_error_occurred', error=str(e))}{Style.RESET_ALL}")
|
||||
return False
|
||||
finally:
|
||||
if conn:
|
||||
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}")
|
||||
|
||||
|
||||
|
||||
@@ -65,238 +65,75 @@ class CursorRegistration:
|
||||
"""设置邮箱"""
|
||||
try:
|
||||
print(f"{Fore.CYAN}{EMOJI['START']} {self.translator.get('register.browser_start')}...{Style.RESET_ALL}")
|
||||
self.browser = self.browser_manager.init_browser()
|
||||
self.controller = BrowserControl(self.browser, self.translator)
|
||||
|
||||
# 打开邮箱生成器页面(第一个标签页)
|
||||
self.controller.navigate_to(self.mail_url)
|
||||
self.email_tab = self.browser # 保存邮箱标签页
|
||||
self.controller.email_tab = self.email_tab # 同时保存到controller
|
||||
# 使用 new_tempemail 创建临时邮箱,传入 translator
|
||||
from new_tempemail import NewTempEmail
|
||||
self.temp_email = NewTempEmail(self.translator) # 传入 translator
|
||||
|
||||
# 生成新邮箱
|
||||
self.controller.generate_new_email()
|
||||
# 创建临时邮箱
|
||||
email_address = self.temp_email.create_email()
|
||||
if not email_address:
|
||||
print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('register.email_create_failed')}{Style.RESET_ALL}")
|
||||
return False
|
||||
|
||||
# 选择随机域名
|
||||
self.controller.select_email_domain()
|
||||
# 保存邮箱地址和浏览器实例
|
||||
self.email_address = email_address
|
||||
self.email_tab = self.temp_email # 传递 NewTempEmail 实例而不是 page
|
||||
self.controller = BrowserControl(self.temp_email.page, self.translator)
|
||||
|
||||
# 获取邮箱地址
|
||||
self.email_address = self.controller.copy_and_get_email()
|
||||
if self.email_address:
|
||||
print(f"{EMOJI['MAIL']}{Fore.CYAN} {self.translator.get('register.get_email_address')}: {self.email_address}{Style.RESET_ALL}")
|
||||
|
||||
# 进入邮箱
|
||||
if self.controller.view_mailbox():
|
||||
return True
|
||||
|
||||
return False
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('register.setup_error', error=str(e))}{Style.RESET_ALL}")
|
||||
print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('register.email_setup_failed', error=str(e))}{Style.RESET_ALL}")
|
||||
return False
|
||||
|
||||
def register_cursor(self):
|
||||
"""注册 Cursor"""
|
||||
signup_browser_manager = None
|
||||
browser_tab = None
|
||||
try:
|
||||
print(f"{Fore.CYAN}{EMOJI['START']} {self.translator.get('register.register_start')}...{Style.RESET_ALL}")
|
||||
|
||||
# 创建新的浏览器实例用于注册
|
||||
from browser import BrowserManager
|
||||
signup_browser_manager = BrowserManager(noheader=True)
|
||||
self.signup_tab = signup_browser_manager.init_browser()
|
||||
# 直接使用 new_signup.py 进行注册
|
||||
from new_signup import main as new_signup_main
|
||||
|
||||
# 访问注册页面
|
||||
self.signup_tab.get(self.sign_up_url)
|
||||
time.sleep(2)
|
||||
|
||||
# 填写注册表单
|
||||
if self.signup_tab.ele("@name=first_name"):
|
||||
print(f"{Fore.CYAN}{EMOJI['FORM']} {self.translator.get('register.filling_form')}...{Style.RESET_ALL}")
|
||||
|
||||
self.signup_tab.ele("@name=first_name").input(self.first_name)
|
||||
time.sleep(random.uniform(1, 2))
|
||||
|
||||
self.signup_tab.ele("@name=last_name").input(self.last_name)
|
||||
time.sleep(random.uniform(1, 2))
|
||||
|
||||
self.signup_tab.ele("@name=email").input(self.email_address)
|
||||
time.sleep(random.uniform(1, 2))
|
||||
|
||||
self.signup_tab.ele("@type=submit").click()
|
||||
print(f"{Fore.GREEN}{EMOJI['SUCCESS']} {self.translator.get('register.basic_info_submitted')}...{Style.RESET_ALL}")
|
||||
|
||||
# 处理 Turnstile 验证
|
||||
self._handle_turnstile()
|
||||
|
||||
# 设置密码
|
||||
if self.signup_tab.ele("@name=password"):
|
||||
print(f"{Fore.CYAN}{EMOJI['PASSWORD']} {self.translator.get('register.set_password')}...{Style.RESET_ALL}")
|
||||
self.signup_tab.ele("@name=password").input(self.password)
|
||||
time.sleep(random.uniform(1, 2))
|
||||
self.signup_tab.ele("@type=submit").click()
|
||||
# 执行新的注册流程,传入 translator
|
||||
result, browser_tab = new_signup_main(
|
||||
email=self.email_address,
|
||||
password=self.password,
|
||||
first_name=self.first_name,
|
||||
last_name=self.last_name,
|
||||
email_tab=self.email_tab,
|
||||
controller=self.controller,
|
||||
translator=self.translator
|
||||
)
|
||||
|
||||
self._handle_turnstile()
|
||||
|
||||
# 等待并获取验证码
|
||||
time.sleep(5) # 等待验证码邮件
|
||||
|
||||
self.browser.refresh()
|
||||
if result:
|
||||
# 使用返回的浏览器实例获取账户信息
|
||||
self.signup_tab = browser_tab # 保存浏览器实例
|
||||
success = self._get_account_info()
|
||||
|
||||
# 获取信息后关闭浏览器
|
||||
if browser_tab:
|
||||
try:
|
||||
browser_tab.quit()
|
||||
except:
|
||||
pass
|
||||
|
||||
return success
|
||||
|
||||
# 获取验证码,设置60秒超时
|
||||
verification_code = None
|
||||
max_attempts = 10 # 增加到10次尝试
|
||||
retry_interval = 5 # 每5秒重试一次
|
||||
start_time = time.time()
|
||||
timeout = 60 # 60秒超时
|
||||
|
||||
print(f"{Fore.CYAN}{EMOJI['WAIT']} {self.translator.get('register.start_getting_verification_code')}...{Style.RESET_ALL}")
|
||||
return False
|
||||
|
||||
for attempt in range(max_attempts):
|
||||
# 检查是否超时
|
||||
if time.time() - start_time > timeout:
|
||||
print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('register.get_verification_code_timeout')}...{Style.RESET_ALL}")
|
||||
break
|
||||
|
||||
verification_code = self.controller.get_verification_code()
|
||||
if verification_code:
|
||||
print(f"{Fore.GREEN}{EMOJI['SUCCESS']} {self.translator.get('register.get_verification_code_success')}: {verification_code}{Style.RESET_ALL}")
|
||||
break
|
||||
|
||||
remaining_time = int(timeout - (time.time() - start_time))
|
||||
print(f"{Fore.YELLOW}{EMOJI['WAIT']} {self.translator.get('register.try_get_verification_code', attempt=attempt + 1, remaining_time=remaining_time)}...{Style.RESET_ALL}")
|
||||
|
||||
# 刷新邮箱
|
||||
self.browser.refresh()
|
||||
time.sleep(retry_interval)
|
||||
|
||||
if verification_code:
|
||||
# 在注册页面填写验证码
|
||||
for i, digit in enumerate(verification_code):
|
||||
self.signup_tab.ele(f"@data-index={i}").input(digit)
|
||||
time.sleep(random.uniform(0.1, 0.3))
|
||||
|
||||
print(f"{Fore.GREEN}{EMOJI['SUCCESS']} {self.translator.get('register.verification_code_filled')}...{Style.RESET_ALL}")
|
||||
time.sleep(3)
|
||||
|
||||
self._handle_turnstile()
|
||||
|
||||
# 检查当前URL
|
||||
current_url = self.signup_tab.url
|
||||
if "authenticator.cursor.sh" in current_url:
|
||||
print(f"{Fore.CYAN}{EMOJI['VERIFY']} {self.translator.get('register.detect_login_page')}...{Style.RESET_ALL}")
|
||||
|
||||
# 填写邮箱
|
||||
email_input = self.signup_tab.ele('@name=email')
|
||||
if email_input:
|
||||
email_input.input(self.email_address)
|
||||
time.sleep(random.uniform(1, 2))
|
||||
|
||||
# 点击提交
|
||||
submit_button = self.signup_tab.ele('@type=submit')
|
||||
if submit_button:
|
||||
submit_button.click()
|
||||
time.sleep(2)
|
||||
|
||||
# 处理 Turnstile 验证
|
||||
self._handle_turnstile()
|
||||
|
||||
# 填写密码
|
||||
password_input = self.signup_tab.ele('@name=password')
|
||||
if password_input:
|
||||
password_input.input(self.password)
|
||||
time.sleep(random.uniform(1, 2))
|
||||
|
||||
# 点击提交
|
||||
submit_button = self.signup_tab.ele('@type=submit')
|
||||
if submit_button:
|
||||
submit_button.click()
|
||||
time.sleep(2)
|
||||
|
||||
# 处理 Turnstile 验证
|
||||
self._handle_turnstile()
|
||||
|
||||
# 等待跳转到设置页面
|
||||
max_wait = 30
|
||||
start_time = time.time()
|
||||
while time.time() - start_time < max_wait:
|
||||
if "cursor.com/settings" in self.signup_tab.url:
|
||||
print(f"{Fore.GREEN}{EMOJI['SUCCESS']} {self.translator.get('register.login_success_and_jump_to_settings_page')}...{Style.RESET_ALL}")
|
||||
break
|
||||
time.sleep(1)
|
||||
|
||||
# 获取账户信息
|
||||
result = self._get_account_info()
|
||||
|
||||
# 关闭注册窗口
|
||||
if signup_browser_manager:
|
||||
signup_browser_manager.quit()
|
||||
|
||||
return result
|
||||
else:
|
||||
print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('register.get_verification_code_timeout')}...{Style.RESET_ALL}")
|
||||
return False
|
||||
|
||||
except Exception as e:
|
||||
print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('register.register_process_error', error=str(e))}{Style.RESET_ALL}")
|
||||
return False
|
||||
finally:
|
||||
# 确保在任何情况下都关闭注册窗口
|
||||
if signup_browser_manager:
|
||||
signup_browser_manager.quit()
|
||||
|
||||
def _handle_turnstile(self):
|
||||
"""处理 Turnstile 验证"""
|
||||
print(f"{Fore.YELLOW}{EMOJI['VERIFY']} {self.translator.get('register.handle_turnstile')}...{Style.RESET_ALL}")
|
||||
|
||||
# 设置最大等待时间(秒)
|
||||
max_wait_time = 10 # 增加等待时间
|
||||
start_time = time.time()
|
||||
|
||||
while True:
|
||||
try:
|
||||
# 检查是否超时
|
||||
if time.time() - start_time > max_wait_time:
|
||||
print(f"{Fore.YELLOW}{EMOJI['WAIT']} {self.translator.get('register.no_turnstile')}...{Style.RESET_ALL}")
|
||||
time.sleep(2)
|
||||
break
|
||||
|
||||
# 确保在任何情况下都关闭浏览器
|
||||
if browser_tab:
|
||||
try:
|
||||
challengeCheck = (
|
||||
self.signup_tab.ele("@id=cf-turnstile", timeout=1)
|
||||
.child()
|
||||
.shadow_root.ele("tag:iframe")
|
||||
.ele("tag:body")
|
||||
.sr("tag:input")
|
||||
)
|
||||
|
||||
if challengeCheck:
|
||||
challengeCheck.click()
|
||||
time.sleep(3)
|
||||
print(f"{Fore.GREEN}{EMOJI['SUCCESS']} {self.translator.get('register.turnstile_passed')}{Style.RESET_ALL}")
|
||||
time.sleep(2)
|
||||
break
|
||||
browser_tab.quit()
|
||||
except:
|
||||
pass
|
||||
|
||||
try:
|
||||
if (self.signup_tab.ele("@name=password", timeout=0.5) or
|
||||
self.signup_tab.ele("@name=email", timeout=0.5) or
|
||||
self.signup_tab.ele("@data-index=0", timeout=0.5)):
|
||||
print(f"{Fore.GREEN}{EMOJI['SUCCESS']} {self.translator.get('register.turnstile_passed')}{Style.RESET_ALL}")
|
||||
time.sleep(2)
|
||||
break
|
||||
except:
|
||||
pass
|
||||
|
||||
time.sleep(1)
|
||||
|
||||
except Exception as e:
|
||||
print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('register.error', error=str(e))}{Style.RESET_ALL}")
|
||||
time.sleep(2)
|
||||
break
|
||||
|
||||
time.sleep(2)
|
||||
|
||||
def _get_account_info(self):
|
||||
"""获取账户信息和 Token"""
|
||||
try:
|
||||
@@ -389,8 +226,12 @@ class CursorRegistration:
|
||||
return True
|
||||
return False
|
||||
finally:
|
||||
if self.browser_manager:
|
||||
self.browser_manager.quit()
|
||||
# 关闭邮箱标签页
|
||||
if hasattr(self, 'temp_email'):
|
||||
try:
|
||||
self.temp_email.close()
|
||||
except:
|
||||
pass
|
||||
|
||||
def update_cursor_auth(self, email=None, access_token=None, refresh_token=None):
|
||||
"""更新Cursor的认证信息的便捷函数"""
|
||||
|
||||
BIN
images/cloudflare_2025-02-12_13-43-21.png
Normal file
BIN
images/cloudflare_2025-02-12_13-43-21.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 288 KiB |
BIN
images/new107_2025-01-15_13-53-56.png
Normal file
BIN
images/new107_2025-01-15_13-53-56.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 55 KiB |
BIN
images/pass_2025-02-08_21-48-36.png
Normal file
BIN
images/pass_2025-02-08_21-48-36.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 137 KiB |
@@ -45,14 +45,46 @@
|
||||
"updating_pair": "Updating Key-Value Pair",
|
||||
"sqlite_success": "SQLite Database Updated Successfully",
|
||||
"sqlite_error": "SQLite Database Update Failed: {error}",
|
||||
"press_enter": "Press Enter to Exit"
|
||||
"press_enter": "Press Enter to Exit",
|
||||
"unsupported_os": "Unsupported OS: {os}",
|
||||
"linux_path_not_found": "Linux Path Not Found",
|
||||
"updating_system_ids": "Updating System IDs",
|
||||
"system_ids_updated": "System IDs Updated Successfully",
|
||||
"system_ids_update_failed": "System IDs Update Failed: {error}",
|
||||
"windows_guid_updated": "Windows GUID Updated Successfully",
|
||||
"windows_permission_denied": "Windows Permission Denied",
|
||||
"windows_guid_update_failed": "Windows GUID Update Failed",
|
||||
"macos_uuid_updated": "macOS UUID Updated Successfully",
|
||||
"plutil_command_failed": "plutil Command Failed",
|
||||
"start_patching": "Starting Patching getMachineId",
|
||||
"macos_uuid_update_failed": "macOS UUID Update Failed",
|
||||
"current_version": "Current Cursor Version: {version}",
|
||||
"patch_completed": "Patching getMachineId Completed",
|
||||
"patch_failed": "Patching getMachineId Failed: {error}",
|
||||
"version_check_passed": "Cursor Version Check Passed",
|
||||
"file_modified": "File Modified"
|
||||
},
|
||||
"register": {
|
||||
"title": "Cursor Registration Tool",
|
||||
"start": "Starting Registration Process",
|
||||
"handling_turnstile": "Handling Turnstile",
|
||||
"retry_verification": "Retry Verification",
|
||||
"detect_turnstile": "Detect Turnstile",
|
||||
"verification_success": "Verification Success",
|
||||
"starting_browser": "Starting Browser",
|
||||
"form_success": "Form Success",
|
||||
"browser_started": "Browser Started",
|
||||
"waiting_for_second_verification": "Waiting for Second Verification",
|
||||
"waiting_for_verification_code": "Waiting for Verification Code",
|
||||
"password_success": "Password Set Successfully",
|
||||
"password_error": "Password Set Failed: {error}",
|
||||
"waiting_for_page_load": "Waiting for Page Load",
|
||||
"first_verification_passed": "First Verification Passed",
|
||||
"mailbox": "Successfully Entered Mailbox",
|
||||
"register_start": "Start Register",
|
||||
"form_submitted": "Form Submitted, Start Verification...",
|
||||
"filling_form": "Fill Form",
|
||||
"visiting_url": "Visiting URL",
|
||||
"basic_info": "Basic Info Submitted",
|
||||
"handle_turnstile": "Handle Turnstile",
|
||||
"no_turnstile": "Not Detect Turnstile",
|
||||
@@ -90,7 +122,8 @@
|
||||
"save_account_info_failed": "Save Account Info Failed",
|
||||
"get_email_address": "Get Email Address",
|
||||
"update_cursor_auth_info": "Update Cursor Auth Info",
|
||||
"register_process_error": "Register Process Error: {error}"
|
||||
"register_process_error": "Register Process Error: {error}",
|
||||
"setting_password": "Setting Password"
|
||||
},
|
||||
"auth": {
|
||||
"title": "Cursor Auth Manager",
|
||||
@@ -107,10 +140,12 @@
|
||||
"reset_machine_id": "Reset Machine ID",
|
||||
"database_connection_closed": "Database Connection Closed",
|
||||
"database_updated_successfully": "Database Updated Successfully",
|
||||
"connected_to_database": "Connected to Database"
|
||||
"connected_to_database": "Connected to Database",
|
||||
"updating_pair": "Updating Key-Value Pair"
|
||||
},
|
||||
"control": {
|
||||
"generate_email": "Generating New Email",
|
||||
"blocked_domain": "Blocked Domain",
|
||||
"select_domain": "Selecting Random Domain",
|
||||
"copy_email": "Copying Email Address",
|
||||
"enter_mailbox": "Entering Mailbox",
|
||||
@@ -136,6 +171,27 @@
|
||||
"get_cursor_session_token": "Get Cursor Session Token",
|
||||
"get_cursor_session_token_success": "Get Cursor Session Token Success",
|
||||
"get_cursor_session_token_failed": "Get Cursor Session Token Failed",
|
||||
"save_token_failed": "Save Token Failed"
|
||||
"save_token_failed": "Save Token Failed",
|
||||
"database_updated_successfully": "Database Updated Successfully",
|
||||
"database_connection_closed": "Database Connection Closed",
|
||||
"no_valid_verification_code": "No Valid Verification Code"
|
||||
},
|
||||
"email": {
|
||||
"starting_browser": "Starting Browser",
|
||||
"visiting_site": "Visiting smailpro.com",
|
||||
"create_success": "Email Created Successfully",
|
||||
"create_failed": "Failed to Create Email",
|
||||
"create_error": "Email Creation Error: {error}",
|
||||
"refreshing": "Refreshing Email",
|
||||
"refresh_success": "Email Refreshed Successfully",
|
||||
"refresh_error": "Email Refresh Error: {error}",
|
||||
"refresh_button_not_found": "Refresh Button Not Found",
|
||||
"verification_found": "Verification Found",
|
||||
"verification_not_found": "Verification Not Found",
|
||||
"verification_error": "Verification Error: {error}",
|
||||
"verification_code_found": "Verification Code Found",
|
||||
"verification_code_not_found": "Verification Code Not Found",
|
||||
"verification_code_error": "Verification Code Error: {error}",
|
||||
"address": "Email Address"
|
||||
}
|
||||
}
|
||||
@@ -26,13 +26,66 @@
|
||||
"timeout": "以下进程未能在规定时间内关闭: {pids}",
|
||||
"error": "关闭 Cursor 进程时发生错误: {error}"
|
||||
},
|
||||
"reset": {
|
||||
"title": "Cursor 机器标识重置工具",
|
||||
"checking": "检查配置文件",
|
||||
"not_found": "配置文件未找到",
|
||||
"no_permission": "无法读取或写入配置文件,请检查文件权限",
|
||||
"reading": "读取当前配置",
|
||||
"creating_backup": "创建配置备份",
|
||||
"backup_exists": "备份文件已存在,跳过备份步骤",
|
||||
"generating": "生成新机器标识",
|
||||
"saving_json": "保存新配置到JSON",
|
||||
"success": "机器标识重置成功",
|
||||
"new_id": "新机器标识",
|
||||
"permission_error": "权限错误: {error}",
|
||||
"run_as_admin": "请尝试以管理员身份运行此程序",
|
||||
"process_error": "重置进程错误: {error}",
|
||||
"updating_sqlite": "更新SQLite数据库",
|
||||
"updating_pair": "更新键值对",
|
||||
"sqlite_success": "SQLite数据库更新成功",
|
||||
"sqlite_error": "SQLite数据库更新失败: {error}",
|
||||
"press_enter": "按回车键退出",
|
||||
"updating_system_ids": "更新系统ID",
|
||||
"system_ids_updated": "系统ID更新成功",
|
||||
"system_ids_update_failed": "系统ID更新失败: {error}",
|
||||
"unsupported_os": "不支持的操作系统: {os}",
|
||||
"linux_path_not_found": "Linux路径未找到",
|
||||
"windows_guid_updated": "Windows GUID更新成功",
|
||||
"windows_permission_denied": "Windows权限拒绝",
|
||||
"windows_guid_update_failed": "Windows GUID更新失败",
|
||||
"macos_uuid_updated": "macOS UUID更新成功",
|
||||
"plutil_command_failed": "plutil命令失败",
|
||||
"macos_uuid_update_failed": "macOS UUID更新失败",
|
||||
"start_patching": "开始修补getMachineId",
|
||||
"current_version": "当前Cursor版本: {version}",
|
||||
"patch_completed": "getMachineId修补完成",
|
||||
"patch_failed": "getMachineId修补失败: {error}",
|
||||
"version_check_passed": "Cursor版本检查通过",
|
||||
"file_modified": "文件已修改"
|
||||
},
|
||||
"register": {
|
||||
"title": "Cursor 注册工具",
|
||||
"start": "开始注册流程",
|
||||
"browser_started": "浏览器已启动",
|
||||
"password_success": "密码设置完成",
|
||||
"password_error": "密码设置失败: {error}",
|
||||
"waiting_for_page_load": "等待页面加载",
|
||||
"mailbox": "成功进入邮箱",
|
||||
"waiting_for_second_verification": "等待第二阶段验证",
|
||||
"waiting_for_verification_code": "等待验证码",
|
||||
"first_verification_passed": "第一阶段验证通过",
|
||||
"register_start": "开始注册流程",
|
||||
"form_submitted": "表单已提交,开始验证...",
|
||||
"filling_form": "填写注册信息",
|
||||
"visiting_url": "访问URL",
|
||||
"basic_info": "基本信息提交完成",
|
||||
"handling_turnstile": "处理 Turnstile 验证",
|
||||
"retry_verification": "重试验证",
|
||||
"detect_turnstile": "检测 Turnstile 验证",
|
||||
"verification_success": "验证成功",
|
||||
"starting_browser": "启动浏览器",
|
||||
"form_success": "表单提交成功",
|
||||
"handle_turnstile": "处理 Turnstile 验证",
|
||||
"no_turnstile": "未检测到 Turnstile 验证",
|
||||
"turnstile_passed": "验证通过",
|
||||
@@ -68,7 +121,9 @@
|
||||
"account_info_saved": "账户信息已保存",
|
||||
"save_account_info_failed": "保存账户信息失败",
|
||||
"get_email_address": "获取邮箱地址",
|
||||
"register_process_error": "注册流程错误: {error}"
|
||||
"register_process_error": "注册流程错误: {error}",
|
||||
"update_cursor_auth_info": "更新Cursor认证信息",
|
||||
"setting_password": "设置密码"
|
||||
},
|
||||
"auth": {
|
||||
"title": "Cursor 认证管理器",
|
||||
@@ -81,13 +136,18 @@
|
||||
"auth_update_failed": "认证信息更新失败: {error}",
|
||||
"auth_file_created": "认证文件已创建",
|
||||
"auth_file_create_failed": "认证文件创建失败: {error}",
|
||||
"press_enter": "按回车键退出"
|
||||
"press_enter": "按回车键退出",
|
||||
"connected_to_database": "已连接到数据库",
|
||||
"database_updated_successfully": "数据库更新成功",
|
||||
"database_connection_closed": "数据库连接已关闭",
|
||||
"updating_pair": "更新键值对"
|
||||
},
|
||||
"control": {
|
||||
"generate_email": "生成新邮箱",
|
||||
"select_domain": "选择随机域名",
|
||||
"copy_email": "复制邮箱地址",
|
||||
"enter_mailbox": "进入邮箱",
|
||||
"blocked_domain": "被屏蔽的域名",
|
||||
"refresh_mailbox": "刷新邮箱",
|
||||
"check_verification": "检查验证码",
|
||||
"verification_found": "找到验证码",
|
||||
@@ -110,6 +170,25 @@
|
||||
"get_cursor_session_token": "获取Cursor Session Token",
|
||||
"get_cursor_session_token_success": "获取Cursor Session Token成功",
|
||||
"get_cursor_session_token_failed": "获取Cursor Session Token失败",
|
||||
"save_token_failed": "保存Token失败"
|
||||
"save_token_failed": "保存Token失败",
|
||||
"no_valid_verification_code": "没有有效的验证码"
|
||||
},
|
||||
"email": {
|
||||
"starting_browser": "启动浏览器",
|
||||
"visiting_site": "访问 smailpro.com",
|
||||
"create_success": "邮箱创建成功",
|
||||
"create_failed": "邮箱创建失败",
|
||||
"create_error": "邮箱创建错误: {error}",
|
||||
"refreshing": "刷新邮箱",
|
||||
"refresh_success": "邮箱刷新成功",
|
||||
"refresh_error": "邮箱刷新错误: {error}",
|
||||
"refresh_button_not_found": "未找到刷新按钮",
|
||||
"verification_found": "找到验证码",
|
||||
"verification_not_found": "未找到验证码",
|
||||
"verification_error": "验证错误: {error}",
|
||||
"verification_code_found": "找到验证码",
|
||||
"verification_code_not_found": "未找到验证码",
|
||||
"verification_code_error": "验证码错误: {error}",
|
||||
"address": "邮箱地址"
|
||||
}
|
||||
}
|
||||
@@ -26,17 +26,70 @@
|
||||
"timeout": "以下進程未能在規定時間內關閉: {pids}",
|
||||
"error": "關閉 Cursor 進程時發生錯誤: {error}"
|
||||
},
|
||||
"reset": {
|
||||
"title": "Cursor 機器標識重置工具",
|
||||
"checking": "檢查配置文件",
|
||||
"not_found": "配置文件未找到",
|
||||
"no_permission": "無法讀取或寫入配置文件,請檢查文件權限",
|
||||
"reading": "讀取當前配置",
|
||||
"creating_backup": "創建配置備份",
|
||||
"backup_exists": "備份文件已存在,跳過備份步驟",
|
||||
"generating": "生成新機器標識",
|
||||
"saving_json": "保存新配置到JSON",
|
||||
"success": "機器標識重置成功",
|
||||
"new_id": "新機器標識",
|
||||
"permission_error": "權限錯誤: {error}",
|
||||
"run_as_admin": "請嘗試以管理員身份運行此程序",
|
||||
"process_error": "重置進程錯誤: {error}",
|
||||
"updating_sqlite": "更新SQLite數據庫",
|
||||
"updating_pair": "更新鍵值對",
|
||||
"sqlite_success": "SQLite數據庫更新成功",
|
||||
"sqlite_error": "SQLite數據庫更新失敗: {error}",
|
||||
"press_enter": "按回車鍵退出",
|
||||
"updating_system_ids": "更新系統ID",
|
||||
"system_ids_updated": "系統ID更新成功",
|
||||
"system_ids_update_failed": "系統ID更新失敗: {error}",
|
||||
"unsupported_os": "不支持的操作系統: {os}",
|
||||
"linux_path_not_found": "Linux路徑未找到",
|
||||
"windows_guid_updated": "Windows GUID更新成功",
|
||||
"windows_permission_denied": "Windows權限拒絕",
|
||||
"windows_guid_update_failed": "Windows GUID更新失敗",
|
||||
"macos_uuid_updated": "macOS UUID更新成功",
|
||||
"plutil_command_failed": "plutil命令失敗",
|
||||
"macos_uuid_update_failed": "macOS UUID更新失敗",
|
||||
"start_patching": "開始修補getMachineId",
|
||||
"current_version": "當前Cursor版本: {version}",
|
||||
"patch_completed": "getMachineId修補完成",
|
||||
"patch_failed": "getMachineId修補失敗: {error}",
|
||||
"version_check_passed": "Cursor版本檢查通過",
|
||||
"file_modified": "文件已修改"
|
||||
},
|
||||
"register": {
|
||||
"title": "Cursor 註冊工具",
|
||||
"start": "開始註冊流程",
|
||||
"mailbox": "成功進入郵箱",
|
||||
"browser_started": "瀏覽器已啟動",
|
||||
"waiting_for_page_load": "等待頁面加載",
|
||||
"password_success": "密碼設置完成",
|
||||
"password_error": "密碼設置失敗: {error}",
|
||||
"visiting_url": "訪問URL",
|
||||
"first_verification_passed": "第一階段驗證通過",
|
||||
"register_start": "開始註冊流程",
|
||||
"form_submitted": "表單已提交,開始驗證...",
|
||||
"waiting_for_second_verification": "等待第二階段驗證",
|
||||
"filling_form": "填寫註冊信息",
|
||||
"basic_info": "基本信息提交完成",
|
||||
"handle_turnstile": "處理 Turnstile 驗證",
|
||||
"no_turnstile": "未檢測到 Turnstile 驗證",
|
||||
"turnstile_passed": "驗證通過",
|
||||
"verification_start": "開始獲取驗證碼",
|
||||
"waiting_for_verification_code": "等待驗證碼",
|
||||
"handling_turnstile": "處理 Turnstile 驗證",
|
||||
"retry_verification": "重試驗證",
|
||||
"detect_turnstile": "檢測 Turnstile 驗證",
|
||||
"verification_success": "驗證成功",
|
||||
"starting_browser": "啟動瀏覽器",
|
||||
"form_success": "表單提交成功",
|
||||
"verification_timeout": "獲取驗證碼超時",
|
||||
"verification_not_found": "未找到驗證碼",
|
||||
"try_get_code": "第 {attempt} 次嘗試獲取驗證碼 | 剩餘時間: {time}秒",
|
||||
@@ -68,7 +121,9 @@
|
||||
"account_info_saved": "賬戶信息已保存",
|
||||
"save_account_info_failed": "保存賬戶信息失敗",
|
||||
"get_email_address": "獲取郵箱地址",
|
||||
"register_process_error": "註冊流程錯誤: {error}"
|
||||
"register_process_error": "註冊流程錯誤: {error}",
|
||||
"update_cursor_auth_info": "更新Cursor認證信息",
|
||||
"setting_password": "設置密碼"
|
||||
},
|
||||
"auth": {
|
||||
"title": "Cursor 認證管理器",
|
||||
@@ -81,7 +136,11 @@
|
||||
"auth_update_failed": "認證信息更新失敗: {error}",
|
||||
"auth_file_created": "認證文件已創建",
|
||||
"auth_file_create_failed": "認證文件創建失敗: {error}",
|
||||
"press_enter": "按回車鍵退出"
|
||||
"press_enter": "按回車鍵退出",
|
||||
"connected_to_database": "已連接到數據庫",
|
||||
"database_updated_successfully": "數據庫更新成功",
|
||||
"database_connection_closed": "數據庫連接已關閉",
|
||||
"updating_pair": "更新鍵值對"
|
||||
},
|
||||
"control": {
|
||||
"generate_email": "生成新郵箱",
|
||||
@@ -110,6 +169,27 @@
|
||||
"get_cursor_session_token": "獲取Cursor Session Token",
|
||||
"get_cursor_session_token_success": "獲取Cursor Session Token成功",
|
||||
"get_cursor_session_token_failed": "獲取Cursor Session Token失敗",
|
||||
"save_token_failed": "保存Token失敗"
|
||||
}
|
||||
"save_token_failed": "保存Token失敗",
|
||||
"blocked_domain": "被屏蔽的域名",
|
||||
"no_valid_verification_code": "沒有有效的驗證碼"
|
||||
},
|
||||
"email": {
|
||||
"starting_browser": "啟動瀏覽器",
|
||||
"visiting_site": "訪問 smailpro.com",
|
||||
"create_success": "郵箱創建成功",
|
||||
"create_failed": "郵箱創建失敗",
|
||||
"create_error": "郵箱創建錯誤: {error}",
|
||||
"refreshing": "刷新郵箱",
|
||||
"refresh_success": "郵箱刷新成功",
|
||||
"refresh_error": "郵箱刷新錯誤: {error}",
|
||||
"refresh_button_not_found": "未找到刷新按鈕",
|
||||
"verification_found": "找到驗證碼",
|
||||
"verification_not_found": "未找到驗證碼",
|
||||
"verification_error": "驗證錯誤: {error}",
|
||||
"verification_code_found": "找到驗證碼",
|
||||
"verification_code_not_found": "未找到驗證碼",
|
||||
"verification_code_error": "驗證碼錯誤: {error}",
|
||||
"address": "郵箱地址"
|
||||
}
|
||||
|
||||
}
|
||||
11
logo.py
11
logo.py
@@ -2,8 +2,14 @@ from colorama import Fore, Style, init
|
||||
from dotenv import load_dotenv
|
||||
import os
|
||||
|
||||
# 加載環境變量獲取版本號
|
||||
load_dotenv()
|
||||
# 獲取當前腳本所在目錄
|
||||
current_dir = os.path.dirname(os.path.abspath(__file__))
|
||||
# 構建.env文件的完整路徑
|
||||
env_path = os.path.join(current_dir, '.env')
|
||||
|
||||
# 加載環境變量,指定.env文件路徑
|
||||
load_dotenv(env_path)
|
||||
# 獲取版本號,如果未找到則使用默認值
|
||||
version = os.getenv('VERSION', '1.0.0')
|
||||
|
||||
# 初始化 colorama
|
||||
@@ -29,6 +35,5 @@ CURSOR_LOGO = f"""
|
||||
def print_logo():
|
||||
print(CURSOR_LOGO)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
print_logo()
|
||||
16
main.py
16
main.py
@@ -42,11 +42,17 @@ class Translator:
|
||||
|
||||
def get(self, key, **kwargs):
|
||||
"""获取翻译文本"""
|
||||
keys = key.split('.')
|
||||
value = self.translations.get(self.current_language, {})
|
||||
for k in keys:
|
||||
value = value.get(k, key)
|
||||
return value.format(**kwargs) if kwargs else value
|
||||
try:
|
||||
keys = key.split('.')
|
||||
value = self.translations.get(self.current_language, {})
|
||||
for k in keys:
|
||||
if isinstance(value, dict):
|
||||
value = value.get(k, key)
|
||||
else:
|
||||
return key # 如果中間值不是字典,返回原始key
|
||||
return value.format(**kwargs) if kwargs else value
|
||||
except Exception:
|
||||
return key # 出現任何錯誤時返回原始key
|
||||
|
||||
def set_language(self, lang_code):
|
||||
"""设置当前语言"""
|
||||
|
||||
562
new_signup.py
Normal file
562
new_signup.py
Normal file
@@ -0,0 +1,562 @@
|
||||
from DrissionPage import ChromiumOptions, ChromiumPage
|
||||
import time
|
||||
import os
|
||||
import signal
|
||||
import random
|
||||
from colorama import Fore, Style
|
||||
|
||||
# 在文件开头添加全局变量
|
||||
_translator = None
|
||||
|
||||
def cleanup_chrome_processes(translator=None):
|
||||
"""清理所有Chrome相关进程"""
|
||||
print("\n正在清理Chrome进程...")
|
||||
try:
|
||||
if os.name == 'nt':
|
||||
os.system('taskkill /F /IM chrome.exe /T 2>nul')
|
||||
os.system('taskkill /F /IM chromedriver.exe /T 2>nul')
|
||||
else:
|
||||
os.system('pkill -f chrome')
|
||||
os.system('pkill -f chromedriver')
|
||||
except Exception as e:
|
||||
if translator:
|
||||
print(f"{Fore.RED}❌ {translator.get('register.cleanup_error', error=str(e))}{Style.RESET_ALL}")
|
||||
else:
|
||||
print(f"清理进程时出错: {e}")
|
||||
|
||||
def signal_handler(signum, frame):
|
||||
"""处理Ctrl+C信号"""
|
||||
global _translator
|
||||
if _translator:
|
||||
print(f"{Fore.CYAN}{_translator.get('register.exit_signal')}{Style.RESET_ALL}")
|
||||
else:
|
||||
print("\n接收到退出信号,正在关闭...")
|
||||
cleanup_chrome_processes(_translator)
|
||||
os._exit(0)
|
||||
|
||||
def simulate_human_input(page, url, translator=None):
|
||||
"""访问网址"""
|
||||
if translator:
|
||||
print(f"{Fore.CYAN}🚀 {translator.get('register.visiting_url')}: {url}{Style.RESET_ALL}")
|
||||
else:
|
||||
print("正在访问网址...")
|
||||
|
||||
# 先访问空白页面
|
||||
page.get('about:blank')
|
||||
time.sleep(random.uniform(1.0, 2.0))
|
||||
|
||||
# 访问目标页面
|
||||
page.get(url)
|
||||
time.sleep(random.uniform(2.0, 3.0)) # 等待页面加载
|
||||
|
||||
def fill_signup_form(page, first_name, last_name, email, translator=None):
|
||||
"""填写注册表单"""
|
||||
try:
|
||||
if translator:
|
||||
print(f"{Fore.CYAN}📧 {translator.get('register.filling_form')}{Style.RESET_ALL}")
|
||||
else:
|
||||
print("\n正在填写注册表单...")
|
||||
|
||||
# 填写名字
|
||||
first_name_input = page.ele("@name=first_name")
|
||||
if first_name_input:
|
||||
first_name_input.input(first_name)
|
||||
time.sleep(random.uniform(0.5, 1.0))
|
||||
|
||||
# 填写姓氏
|
||||
last_name_input = page.ele("@name=last_name")
|
||||
if last_name_input:
|
||||
last_name_input.input(last_name)
|
||||
time.sleep(random.uniform(0.5, 1.0))
|
||||
|
||||
# 填写邮箱
|
||||
email_input = page.ele("@name=email")
|
||||
if email_input:
|
||||
email_input.input(email)
|
||||
time.sleep(random.uniform(0.5, 1.0))
|
||||
|
||||
# 点击提交按钮
|
||||
submit_button = page.ele("@type=submit")
|
||||
if submit_button:
|
||||
submit_button.click()
|
||||
time.sleep(random.uniform(2.0, 3.0))
|
||||
|
||||
if translator:
|
||||
print(f"{Fore.GREEN}✅ {translator.get('register.form_success')}{Style.RESET_ALL}")
|
||||
else:
|
||||
print("表单填写完成")
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
if translator:
|
||||
print(f"{Fore.RED}❌ {translator.get('register.form_error', error=str(e))}{Style.RESET_ALL}")
|
||||
else:
|
||||
print(f"填写表单时出错: {e}")
|
||||
return False
|
||||
|
||||
def setup_driver(translator=None):
|
||||
"""设置浏览器驱动"""
|
||||
co = ChromiumOptions()
|
||||
|
||||
# 使用无痕模式
|
||||
co.set_argument("--incognito")
|
||||
|
||||
# 设置随机端口
|
||||
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 page
|
||||
|
||||
def handle_turnstile(page, translator=None):
|
||||
"""处理 Turnstile 验证"""
|
||||
try:
|
||||
if translator:
|
||||
print(f"{Fore.CYAN}🔄 {translator.get('register.handling_turnstile')}{Style.RESET_ALL}")
|
||||
else:
|
||||
print("\n正在处理 Turnstile 验证...")
|
||||
|
||||
max_retries = 2
|
||||
retry_count = 0
|
||||
|
||||
while retry_count < max_retries:
|
||||
retry_count += 1
|
||||
if translator:
|
||||
print(f"{Fore.CYAN}🔄 {translator.get('register.retry_verification', attempt=retry_count)}{Style.RESET_ALL}")
|
||||
else:
|
||||
print(f"第 {retry_count} 次尝试验证...")
|
||||
|
||||
try:
|
||||
# 尝试重置 turnstile
|
||||
page.run_js("try { turnstile.reset() } catch(e) { }")
|
||||
time.sleep(2)
|
||||
|
||||
# 定位验证框元素
|
||||
challenge_check = (
|
||||
page.ele("@id=cf-turnstile", timeout=2)
|
||||
.child()
|
||||
.shadow_root.ele("tag:iframe")
|
||||
.ele("tag:body")
|
||||
.sr("tag:input")
|
||||
)
|
||||
|
||||
if challenge_check:
|
||||
if translator:
|
||||
print(f"{Fore.CYAN}🔄 {translator.get('register.detect_turnstile')}{Style.RESET_ALL}")
|
||||
else:
|
||||
print("检测到验证框...")
|
||||
|
||||
# 随机延时后点击验证
|
||||
time.sleep(random.uniform(1, 3))
|
||||
challenge_check.click()
|
||||
time.sleep(2)
|
||||
|
||||
# 检查验证结果
|
||||
if check_verification_success(page, translator):
|
||||
if translator:
|
||||
print(f"{Fore.GREEN}✅ {translator.get('register.verification_success')}{Style.RESET_ALL}")
|
||||
else:
|
||||
print("验证通过!")
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
if translator:
|
||||
print(f"{Fore.RED}❌ {translator.get('register.verification_failed')}{Style.RESET_ALL}")
|
||||
else:
|
||||
print(f"验证尝试失败: {e}")
|
||||
|
||||
# 检查是否已经验证成功
|
||||
if check_verification_success(page, translator):
|
||||
if translator:
|
||||
print(f"{Fore.GREEN}✅ {translator.get('register.verification_success')}{Style.RESET_ALL}")
|
||||
else:
|
||||
print("验证通过!")
|
||||
return True
|
||||
|
||||
time.sleep(random.uniform(1, 2))
|
||||
|
||||
if translator:
|
||||
print(f"{Fore.RED}❌ {translator.get('register.verification_failed')}{Style.RESET_ALL}")
|
||||
else:
|
||||
print("超出最大重试次数")
|
||||
return False
|
||||
|
||||
except Exception as e:
|
||||
if translator:
|
||||
print(f"{Fore.RED}❌ {translator.get('register.verification_error', error=str(e))}{Style.RESET_ALL}")
|
||||
else:
|
||||
print(f"验证过程出错: {e}")
|
||||
return False
|
||||
|
||||
def check_verification_success(page, translator=None):
|
||||
"""检查验证是否成功"""
|
||||
try:
|
||||
# 检查是否存在后续表单元素,这表示验证已通过
|
||||
if (page.ele("@name=password", timeout=0.5) or
|
||||
page.ele("@name=email", timeout=0.5) or
|
||||
page.ele("@data-index=0", timeout=0.5) or
|
||||
page.ele("Account Settings", timeout=0.5)):
|
||||
return True
|
||||
|
||||
# 检查是否出现错误消息
|
||||
error_messages = [
|
||||
'xpath://div[contains(text(), "Can\'t verify the user is human")]',
|
||||
'xpath://div[contains(text(), "Error: 600010")]',
|
||||
'xpath://div[contains(text(), "Please try again")]'
|
||||
]
|
||||
|
||||
for error_xpath in error_messages:
|
||||
if page.ele(error_xpath):
|
||||
return False
|
||||
|
||||
return False
|
||||
except:
|
||||
return False
|
||||
|
||||
def generate_password(length=12):
|
||||
"""生成随机密码"""
|
||||
chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!@#$%^&*"
|
||||
return ''.join(random.choices(chars, k=length))
|
||||
|
||||
def fill_password(page, password, translator=None):
|
||||
"""填写密码"""
|
||||
try:
|
||||
if translator:
|
||||
print(f"{Fore.CYAN}🔑 {translator.get('register.setting_password')}{Style.RESET_ALL}")
|
||||
else:
|
||||
print("\n正在设置密码...")
|
||||
password_input = page.ele("@name=password")
|
||||
if password_input:
|
||||
password_input.input(password)
|
||||
time.sleep(random.uniform(0.5, 1.0))
|
||||
|
||||
submit_button = page.ele("@type=submit")
|
||||
if submit_button:
|
||||
submit_button.click()
|
||||
time.sleep(random.uniform(2.0, 3.0))
|
||||
|
||||
if translator:
|
||||
print(f"{Fore.GREEN}✅ {translator.get('register.password_success')}{Style.RESET_ALL}")
|
||||
else:
|
||||
print(f"密码设置完成: {password}")
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
if translator:
|
||||
print(f"{Fore.RED}❌ {translator.get('register.password_error', error=str(e))}{Style.RESET_ALL}")
|
||||
else:
|
||||
print(f"设置密码时出错: {e}")
|
||||
return False
|
||||
|
||||
def handle_verification_code(browser_tab, email_tab, controller, email, password, translator=None):
|
||||
"""处理验证码"""
|
||||
try:
|
||||
if translator:
|
||||
print(f"\n{Fore.CYAN}{translator.get('register.waiting_for_verification_code')}{Style.RESET_ALL}")
|
||||
else:
|
||||
print("\n等待并获取验证码...")
|
||||
|
||||
# 添加调试信息
|
||||
print(f"\n{Fore.CYAN}DEBUG: email_tab exists: {email_tab is not None}{Style.RESET_ALL}")
|
||||
|
||||
time.sleep(5) # 等待验证码邮件
|
||||
|
||||
# 使用已有的 email_tab 刷新邮箱
|
||||
email_tab.refresh_inbox()
|
||||
time.sleep(3)
|
||||
|
||||
# 检查邮箱是否有验证码邮件
|
||||
if email_tab.check_for_cursor_email():
|
||||
verification_code = email_tab.get_verification_code()
|
||||
if verification_code:
|
||||
# 在注册页面填写验证码
|
||||
for i, digit in enumerate(verification_code):
|
||||
browser_tab.ele(f"@data-index={i}").input(digit)
|
||||
time.sleep(random.uniform(0.1, 0.3))
|
||||
if translator:
|
||||
print(f"{Fore.GREEN}✅ {translator.get('register.verification_success')}{Style.RESET_ALL}")
|
||||
else:
|
||||
print("验证码填写完成")
|
||||
time.sleep(3)
|
||||
|
||||
# 处理最后一次 Turnstile 验证
|
||||
if handle_turnstile(browser_tab, translator):
|
||||
if translator:
|
||||
print(f"{Fore.GREEN}✅ {translator.get('register.verification_success')}{Style.RESET_ALL}")
|
||||
else:
|
||||
print("最后一次验证通过!")
|
||||
time.sleep(2)
|
||||
|
||||
# 访问设置页面
|
||||
if translator:
|
||||
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")
|
||||
time.sleep(3) # 等待页面加载
|
||||
return True
|
||||
else:
|
||||
print("最后一次验证失败")
|
||||
return False
|
||||
|
||||
return False
|
||||
|
||||
# 获取验证码,设置超时
|
||||
verification_code = None
|
||||
max_attempts = 20
|
||||
retry_interval = 10
|
||||
start_time = time.time()
|
||||
timeout = 160
|
||||
|
||||
if translator:
|
||||
print(f"{Fore.CYAN}{translator.get('register.start_getting_verification_code')}{Style.RESET_ALL}")
|
||||
else:
|
||||
print("开始获取验证码...")
|
||||
|
||||
for attempt in range(max_attempts):
|
||||
# 检查是否超时
|
||||
if time.time() - start_time > timeout:
|
||||
if translator:
|
||||
print(f"{Fore.RED}❌ {translator.get('register.verification_timeout')}{Style.RESET_ALL}")
|
||||
else:
|
||||
print("获取验证码超时...")
|
||||
break
|
||||
|
||||
verification_code = controller.get_verification_code()
|
||||
if verification_code:
|
||||
if translator:
|
||||
print(f"{Fore.GREEN}✅ {translator.get('register.verification_success')}{Style.RESET_ALL}")
|
||||
else:
|
||||
print(f"成功获取验证码: {verification_code}")
|
||||
break
|
||||
|
||||
remaining_time = int(timeout - (time.time() - start_time))
|
||||
if translator:
|
||||
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()
|
||||
time.sleep(retry_interval)
|
||||
|
||||
if verification_code:
|
||||
# 在注册页面填写验证码
|
||||
for i, digit in enumerate(verification_code):
|
||||
browser_tab.ele(f"@data-index={i}").input(digit)
|
||||
time.sleep(random.uniform(0.1, 0.3))
|
||||
|
||||
if translator:
|
||||
print(f"{Fore.GREEN}✅ {translator.get('register.verification_success')}{Style.RESET_ALL}")
|
||||
else:
|
||||
print("验证码填写完成")
|
||||
time.sleep(3)
|
||||
|
||||
# 处理最后一次 Turnstile 验证
|
||||
if handle_turnstile(browser_tab, translator):
|
||||
if translator:
|
||||
print(f"{Fore.GREEN}✅ {translator.get('register.verification_success')}{Style.RESET_ALL}")
|
||||
else:
|
||||
print("最后一次验证通过!")
|
||||
time.sleep(2)
|
||||
|
||||
# 直接访问设置页面
|
||||
if translator:
|
||||
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")
|
||||
time.sleep(3) # 等待页面加载
|
||||
|
||||
# 直接返回成功,让 cursor_register.py 处理账户信息获取
|
||||
return True
|
||||
|
||||
else:
|
||||
if translator:
|
||||
print(f"{Fore.RED}❌ {translator.get('register.verification_failed')}{Style.RESET_ALL}")
|
||||
else:
|
||||
print("最后一次验证失败")
|
||||
return False
|
||||
|
||||
return False
|
||||
|
||||
except Exception as e:
|
||||
if translator:
|
||||
print(f"{Fore.RED}❌ {translator.get('register.verification_error', error=str(e))}{Style.RESET_ALL}")
|
||||
else:
|
||||
print(f"处理验证码时出错: {e}")
|
||||
return False
|
||||
|
||||
def handle_sign_in(browser_tab, email, password, translator=None):
|
||||
"""处理登录流程"""
|
||||
try:
|
||||
# 检查是否在登录页面
|
||||
sign_in_header = browser_tab.ele('xpath://h1[contains(text(), "Sign in")]')
|
||||
if not sign_in_header:
|
||||
return True # 如果不是登录页面,说明已经登录成功
|
||||
|
||||
print(f"{Fore.CYAN}检测到登录页面,开始登录...{Style.RESET_ALL}")
|
||||
|
||||
# 填写邮箱
|
||||
email_input = browser_tab.ele('@name=email')
|
||||
if email_input:
|
||||
email_input.input(email)
|
||||
time.sleep(1)
|
||||
|
||||
# 点击 Continue
|
||||
continue_button = browser_tab.ele('xpath://button[contains(@class, "BrandedButton") and text()="Continue"]')
|
||||
if continue_button:
|
||||
continue_button.click()
|
||||
time.sleep(2)
|
||||
|
||||
# 处理 Turnstile 验证
|
||||
if handle_turnstile(browser_tab, translator):
|
||||
# 填写密码
|
||||
password_input = browser_tab.ele('@name=password')
|
||||
if password_input:
|
||||
password_input.input(password)
|
||||
time.sleep(1)
|
||||
|
||||
# 点击 Sign in
|
||||
sign_in_button = browser_tab.ele('xpath://button[@name="intent" and @value="password"]')
|
||||
if sign_in_button:
|
||||
sign_in_button.click()
|
||||
time.sleep(2)
|
||||
|
||||
# 处理最后一次 Turnstile 验证
|
||||
if handle_turnstile(browser_tab, translator):
|
||||
print(f"{Fore.GREEN}登录成功!{Style.RESET_ALL}")
|
||||
time.sleep(3)
|
||||
return True
|
||||
|
||||
print(f"{Fore.RED}登录失败{Style.RESET_ALL}")
|
||||
return False
|
||||
|
||||
except Exception as e:
|
||||
print(f"{Fore.RED}登录过程出错: {str(e)}{Style.RESET_ALL}")
|
||||
return False
|
||||
|
||||
def main(email=None, password=None, first_name=None, last_name=None, email_tab=None, controller=None, translator=None):
|
||||
"""主函数,可以接收账号信息、邮箱标签页和翻译器"""
|
||||
global _translator
|
||||
_translator = translator # 保存到全局变量
|
||||
|
||||
signal.signal(signal.SIGINT, signal_handler)
|
||||
signal.signal(signal.SIGTERM, signal_handler)
|
||||
|
||||
page = None
|
||||
success = False
|
||||
try:
|
||||
page = setup_driver(translator)
|
||||
if translator:
|
||||
print(f"{Fore.CYAN}🚀 {translator.get('register.browser_started')}{Style.RESET_ALL}")
|
||||
else:
|
||||
print("浏览器已启动")
|
||||
|
||||
# 访问注册页面
|
||||
url = "https://authenticator.cursor.sh/sign-up"
|
||||
if translator:
|
||||
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)
|
||||
if translator:
|
||||
print(f"{Fore.CYAN}{translator.get('register.waiting_for_page_load')}{Style.RESET_ALL}")
|
||||
else:
|
||||
print("等待页面加载...")
|
||||
time.sleep(5)
|
||||
|
||||
# 如果没有提供账号信息,则生成随机信息
|
||||
if not all([email, password, first_name, last_name]):
|
||||
first_name = ''.join(random.choices('abcdefghijklmnopqrstuvwxyz', k=6)).capitalize()
|
||||
last_name = ''.join(random.choices('abcdefghijklmnopqrstuvwxyz', k=6)).capitalize()
|
||||
email = f"{first_name.lower()}{random.randint(100,999)}@example.com"
|
||||
password = generate_password()
|
||||
|
||||
# 保存账号信息
|
||||
with open('test_accounts.txt', 'a', encoding='utf-8') as f:
|
||||
f.write(f"\n{'='*50}\n")
|
||||
f.write(f"Email: {email}\n")
|
||||
f.write(f"Password: {password}\n")
|
||||
f.write(f"{'='*50}\n")
|
||||
|
||||
# 填写表单
|
||||
if fill_signup_form(page, first_name, last_name, email, translator):
|
||||
if translator:
|
||||
print(f"\n{Fore.GREEN}{translator.get('register.form_submitted')}{Style.RESET_ALL}")
|
||||
else:
|
||||
print("\n表单已提交,开始验证...")
|
||||
|
||||
# 处理第一次 Turnstile 验证
|
||||
if handle_turnstile(page, translator):
|
||||
if translator:
|
||||
print(f"\n{Fore.GREEN}{translator.get('register.first_verification_passed')}{Style.RESET_ALL}")
|
||||
else:
|
||||
print("\n第一阶段验证通过!")
|
||||
|
||||
# 填写密码
|
||||
if fill_password(page, password, translator):
|
||||
if translator:
|
||||
print(f"\n{Fore.CYAN}{translator.get('register.waiting_for_second_verification')}{Style.RESET_ALL}")
|
||||
else:
|
||||
print("\n等待第二次验证...")
|
||||
time.sleep(2)
|
||||
|
||||
# 处理第二次 Turnstile 验证
|
||||
if handle_turnstile(page, translator):
|
||||
if translator:
|
||||
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 translator:
|
||||
print(f"\n{Fore.GREEN}{translator.get('register.verification_success')}{Style.RESET_ALL}")
|
||||
else:
|
||||
print("\n注册流程完成!")
|
||||
success = True
|
||||
return True, page # 返回成功状态和浏览器实例
|
||||
else:
|
||||
print("\n验证码处理失败")
|
||||
else:
|
||||
print("\n第二次验证失败")
|
||||
else:
|
||||
print("\n密码设置失败")
|
||||
else:
|
||||
print("\n第一次验证失败")
|
||||
|
||||
return False, None
|
||||
|
||||
except Exception as e:
|
||||
print(f"发生错误: {e}")
|
||||
return False, None
|
||||
finally:
|
||||
if page and not success: # 只在失败时清理
|
||||
try:
|
||||
page.quit()
|
||||
except:
|
||||
pass
|
||||
cleanup_chrome_processes(translator)
|
||||
|
||||
if __name__ == "__main__":
|
||||
main() # 直接运行时不传参数,使用随机生成的信息
|
||||
226
new_tempemail.py
Normal file
226
new_tempemail.py
Normal file
@@ -0,0 +1,226 @@
|
||||
from DrissionPage import ChromiumPage, ChromiumOptions
|
||||
import time
|
||||
import os
|
||||
import sys
|
||||
from colorama import Fore, Style, init
|
||||
|
||||
# 初始化 colorama
|
||||
init()
|
||||
|
||||
class NewTempEmail:
|
||||
def __init__(self, translator=None):
|
||||
self.translator = translator
|
||||
self.page = None
|
||||
self.setup_browser()
|
||||
|
||||
def get_extension_block(self):
|
||||
"""获取插件路径"""
|
||||
root_dir = os.getcwd()
|
||||
extension_path = os.path.join(root_dir, "uBlock0.chromium")
|
||||
|
||||
if hasattr(sys, "_MEIPASS"):
|
||||
extension_path = os.path.join(sys._MEIPASS, "uBlock0.chromium")
|
||||
|
||||
if not os.path.exists(extension_path):
|
||||
raise FileNotFoundError(f"插件不存在: {extension_path}")
|
||||
|
||||
return extension_path
|
||||
|
||||
def setup_browser(self):
|
||||
"""设置浏览器"""
|
||||
try:
|
||||
if self.translator:
|
||||
print(f"{Fore.CYAN}ℹ️ {self.translator.get('email.starting_browser')}{Style.RESET_ALL}")
|
||||
else:
|
||||
print(f"{Fore.CYAN}ℹ️ 正在启动浏览器...{Style.RESET_ALL}")
|
||||
|
||||
# 创建浏览器选项
|
||||
co = ChromiumOptions()
|
||||
co.set_argument("--headless=new")
|
||||
|
||||
co.auto_port() # 自动设置端口
|
||||
|
||||
# 加载 uBlock 插件
|
||||
try:
|
||||
extension_path = self.get_extension_block()
|
||||
co.set_argument("--allow-extensions-in-incognito")
|
||||
co.add_extension(extension_path)
|
||||
except Exception as e:
|
||||
if self.translator:
|
||||
print(f"{Fore.YELLOW}⚠️ {self.translator.get('email.extension_load_error')}: {str(e)}{Style.RESET_ALL}")
|
||||
else:
|
||||
print(f"{Fore.YELLOW}⚠️ 加载插件失败: {str(e)}{Style.RESET_ALL}")
|
||||
|
||||
self.page = ChromiumPage(co)
|
||||
return True
|
||||
except Exception as e:
|
||||
if self.translator:
|
||||
print(f"{Fore.RED}❌ {self.translator.get('email.browser_start_error')}: {str(e)}{Style.RESET_ALL}")
|
||||
else:
|
||||
print(f"{Fore.RED}❌ 启动浏览器失败: {str(e)}{Style.RESET_ALL}")
|
||||
return False
|
||||
|
||||
def create_email(self):
|
||||
"""创建临时邮箱"""
|
||||
try:
|
||||
if self.translator:
|
||||
print(f"{Fore.CYAN}ℹ️ {self.translator.get('email.visiting_site')}{Style.RESET_ALL}")
|
||||
else:
|
||||
print(f"{Fore.CYAN}ℹ️ 正在访问 smailpro.com...{Style.RESET_ALL}")
|
||||
|
||||
# 访问网站
|
||||
self.page.get("https://smailpro.com/")
|
||||
time.sleep(2)
|
||||
|
||||
# 点击创建邮箱按钮
|
||||
create_button = self.page.ele('xpath://button[@title="Create temporary email"]')
|
||||
if create_button:
|
||||
create_button.click()
|
||||
time.sleep(1)
|
||||
|
||||
# 点击弹窗中的 Create 按钮
|
||||
modal_create_button = self.page.ele('xpath://button[contains(text(), "Create")]')
|
||||
if modal_create_button:
|
||||
modal_create_button.click()
|
||||
time.sleep(2)
|
||||
|
||||
# 获取邮箱地址 - 修改选择器
|
||||
email_div = self.page.ele('xpath://div[@class="text-base sm:text-lg md:text-xl text-gray-700"]')
|
||||
if email_div:
|
||||
email = email_div.text.strip()
|
||||
if '@' in email: # 验证是否是有效的邮箱地址
|
||||
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
|
||||
if self.translator:
|
||||
print(f"{Fore.RED}❌ {self.translator.get('email.create_failed')}{Style.RESET_ALL}")
|
||||
else:
|
||||
print(f"{Fore.RED}❌ 创建邮箱失败{Style.RESET_ALL}")
|
||||
return None
|
||||
|
||||
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):
|
||||
"""关闭浏览器"""
|
||||
if self.page:
|
||||
self.page.quit()
|
||||
|
||||
def refresh_inbox(self):
|
||||
"""刷新邮箱"""
|
||||
try:
|
||||
if self.translator:
|
||||
print(f"{Fore.CYAN}🔄 {self.translator.get('email.refreshing')}{Style.RESET_ALL}")
|
||||
else:
|
||||
print(f"{Fore.CYAN}🔄 正在刷新邮箱...{Style.RESET_ALL}")
|
||||
|
||||
# 点击刷新按钮
|
||||
refresh_button = self.page.ele('xpath://button[@id="refresh"]')
|
||||
if refresh_button:
|
||||
refresh_button.click()
|
||||
time.sleep(2) # 等待刷新完成
|
||||
if self.translator:
|
||||
print(f"{Fore.GREEN}✅ {self.translator.get('email.refresh_success')}{Style.RESET_ALL}")
|
||||
else:
|
||||
print(f"{Fore.GREEN}✅ 邮箱刷新成功{Style.RESET_ALL}")
|
||||
return True
|
||||
|
||||
if self.translator:
|
||||
print(f"{Fore.RED}❌ {self.translator.get('email.refresh_button_not_found')}{Style.RESET_ALL}")
|
||||
else:
|
||||
print(f"{Fore.RED}❌ 未找到刷新按钮{Style.RESET_ALL}")
|
||||
return False
|
||||
|
||||
except Exception as e:
|
||||
if self.translator:
|
||||
print(f"{Fore.RED}❌ {self.translator.get('email.refresh_error')}: {str(e)}{Style.RESET_ALL}")
|
||||
else:
|
||||
print(f"{Fore.RED}❌ 刷新邮箱出错: {str(e)}{Style.RESET_ALL}")
|
||||
return False
|
||||
|
||||
def check_for_cursor_email(self):
|
||||
"""检查是否有 Cursor 的验证邮件"""
|
||||
try:
|
||||
# 查找验证邮件 - 使用更精确的选择器
|
||||
email_div = self.page.ele('xpath://div[contains(@class, "p-2") and contains(@class, "cursor-pointer") and contains(@class, "bg-white") and contains(@class, "shadow") and .//b[text()="no-reply@cursor.sh"] and .//span[text()="Verify your email address"]]')
|
||||
if email_div:
|
||||
if self.translator:
|
||||
print(f"{Fore.GREEN}✅ {self.translator.get('email.verification_found')}{Style.RESET_ALL}")
|
||||
else:
|
||||
print(f"{Fore.GREEN}✅ 找到验证邮件{Style.RESET_ALL}")
|
||||
# 使用 JavaScript 点击元素
|
||||
self.page.run_js('arguments[0].click()', email_div)
|
||||
time.sleep(2) # 等待邮件内容加载
|
||||
return True
|
||||
if self.translator:
|
||||
print(f"{Fore.YELLOW}⚠️ {self.translator.get('email.verification_not_found')}{Style.RESET_ALL}")
|
||||
else:
|
||||
print(f"{Fore.YELLOW}⚠️ 未找到验证邮件{Style.RESET_ALL}")
|
||||
return False
|
||||
|
||||
except Exception as e:
|
||||
if self.translator:
|
||||
print(f"{Fore.RED}❌ {self.translator.get('email.verification_error')}: {str(e)}{Style.RESET_ALL}")
|
||||
else:
|
||||
print(f"{Fore.RED}❌ 检查验证邮件出错: {str(e)}{Style.RESET_ALL}")
|
||||
return False
|
||||
|
||||
def get_verification_code(self):
|
||||
"""获取验证码"""
|
||||
try:
|
||||
# 查找验证码元素
|
||||
code_element = self.page.ele('xpath://td//div[contains(@style, "font-size:28px") and contains(@style, "letter-spacing:2px")]')
|
||||
if code_element:
|
||||
code = code_element.text.strip()
|
||||
if code.isdigit() and len(code) == 6:
|
||||
if self.translator:
|
||||
print(f"{Fore.GREEN}✅ {self.translator.get('email.verification_code_found')}: {code}{Style.RESET_ALL}")
|
||||
else:
|
||||
print(f"{Fore.GREEN}✅ 获取验证码成功: {code}{Style.RESET_ALL}")
|
||||
return code
|
||||
if self.translator:
|
||||
print(f"{Fore.YELLOW}⚠️ {self.translator.get('email.verification_code_not_found')}{Style.RESET_ALL}")
|
||||
else:
|
||||
print(f"{Fore.YELLOW}⚠️ 未找到有效的验证码{Style.RESET_ALL}")
|
||||
return None
|
||||
|
||||
except Exception as e:
|
||||
if self.translator:
|
||||
print(f"{Fore.RED}❌ {self.translator.get('email.verification_code_error')}: {str(e)}{Style.RESET_ALL}")
|
||||
else:
|
||||
print(f"{Fore.RED}❌ 获取验证码出错: {str(e)}{Style.RESET_ALL}")
|
||||
return None
|
||||
|
||||
def main(translator=None):
|
||||
temp_email = NewTempEmail(translator)
|
||||
|
||||
try:
|
||||
email = temp_email.create_email()
|
||||
if email:
|
||||
if translator:
|
||||
print(f"\n{Fore.CYAN}📧 {translator.get('email.address')}: {email}{Style.RESET_ALL}")
|
||||
else:
|
||||
print(f"\n{Fore.CYAN}📧 临时邮箱地址: {email}{Style.RESET_ALL}")
|
||||
|
||||
# 测试刷新功能
|
||||
while True:
|
||||
if translator:
|
||||
choice = input(f"\n{translator.get('email.refresh_prompt')}: ").lower()
|
||||
else:
|
||||
choice = input("\n按 R 刷新邮箱,按 Q 退出: ").lower()
|
||||
if choice == 'r':
|
||||
temp_email.refresh_inbox()
|
||||
elif choice == 'q':
|
||||
break
|
||||
|
||||
finally:
|
||||
temp_email.close()
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -1,22 +0,0 @@
|
||||
{
|
||||
"manifest_version": 3,
|
||||
"name": "Recaptcha Blocker",
|
||||
"version": "1.0",
|
||||
"description": "Blocks reCAPTCHA from loading",
|
||||
"content_scripts": [
|
||||
{
|
||||
"matches": ["*://yopmail.com/zh/wm*"],
|
||||
"js": ["script.js"],
|
||||
"run_at": "document_start",
|
||||
"all_frames": true
|
||||
}
|
||||
],
|
||||
"permissions": [
|
||||
"webNavigation",
|
||||
"activeTab"
|
||||
],
|
||||
"host_permissions": [
|
||||
"*://yopmail.com/*",
|
||||
"*://*.google.com/*"
|
||||
]
|
||||
}
|
||||
@@ -1,123 +0,0 @@
|
||||
// Debug logging function
|
||||
function log(message) {
|
||||
console.log(`[reCAPTCHA Bypass] ${new Date().toISOString()}: ${message}`);
|
||||
}
|
||||
|
||||
// Function to get element by selector
|
||||
function qSelector(selector) {
|
||||
return document.querySelector(selector);
|
||||
}
|
||||
|
||||
// Constants
|
||||
const MAX_ATTEMPTS = 1;
|
||||
const SELECTORS = {
|
||||
CHECK_BOX: ".recaptcha-checkbox-border",
|
||||
AUDIO_BUTTON: "#recaptcha-audio-button",
|
||||
PLAY_BUTTON: ".rc-audiochallenge-play-button .rc-button-default",
|
||||
AUDIO_SOURCE: "#audio-source",
|
||||
IMAGE_SELECT: "#rc-imageselect",
|
||||
RESPONSE_FIELD: ".rc-audiochallenge-response-field",
|
||||
AUDIO_ERROR_MESSAGE: ".rc-audiochallenge-error-message",
|
||||
AUDIO_RESPONSE: "#audio-response",
|
||||
RELOAD_BUTTON: "#recaptcha-reload-button",
|
||||
RECAPTCHA_STATUS: "#recaptcha-accessible-status",
|
||||
DOSCAPTCHA: ".rc-doscaptcha-body",
|
||||
VERIFY_BUTTON: "#recaptcha-verify-button"
|
||||
};
|
||||
|
||||
// Function to check if element is hidden
|
||||
function isHidden(el) {
|
||||
return (el.offsetParent === null);
|
||||
}
|
||||
|
||||
// Function to handle the bypass process
|
||||
async function bypassRecaptcha() {
|
||||
try {
|
||||
log('Starting bypass process...');
|
||||
log('Waiting 3 seconds before starting...');
|
||||
await new Promise(resolve => setTimeout(resolve, 3000));
|
||||
|
||||
let solved = false;
|
||||
let checkBoxClicked = false;
|
||||
let requestCount = 0;
|
||||
|
||||
const recaptchaInitialStatus = qSelector(SELECTORS.RECAPTCHA_STATUS) ?
|
||||
qSelector(SELECTORS.RECAPTCHA_STATUS).innerText : "";
|
||||
|
||||
log('Initial reCAPTCHA status: ' + recaptchaInitialStatus);
|
||||
|
||||
// Main bypass logic
|
||||
try {
|
||||
if (!checkBoxClicked && qSelector(SELECTORS.CHECK_BOX) &&
|
||||
!isHidden(qSelector(SELECTORS.CHECK_BOX))) {
|
||||
log('Clicking checkbox...');
|
||||
qSelector(SELECTORS.CHECK_BOX).click();
|
||||
checkBoxClicked = true;
|
||||
}
|
||||
|
||||
// Check if the captcha is solved
|
||||
if (qSelector(SELECTORS.RECAPTCHA_STATUS) &&
|
||||
(qSelector(SELECTORS.RECAPTCHA_STATUS).innerText != recaptchaInitialStatus)) {
|
||||
solved = true;
|
||||
log('SOLVED!');
|
||||
}
|
||||
|
||||
if (requestCount > MAX_ATTEMPTS) {
|
||||
log('Attempted Max Retries. Stopping the solver');
|
||||
solved = true;
|
||||
}
|
||||
|
||||
// Stop solving when Automated queries message is shown
|
||||
if (qSelector(SELECTORS.DOSCAPTCHA) &&
|
||||
qSelector(SELECTORS.DOSCAPTCHA).innerText.length > 0) {
|
||||
log('Automated Queries Detected');
|
||||
}
|
||||
|
||||
} catch (err) {
|
||||
log(`Error in main bypass logic: ${err.message}`);
|
||||
}
|
||||
|
||||
log('Bypass process completed');
|
||||
|
||||
// If not solved, retry after delay
|
||||
if (!solved && requestCount < MAX_ATTEMPTS) {
|
||||
requestCount++;
|
||||
log(`Retrying... Attempt ${requestCount} of ${MAX_ATTEMPTS}`);
|
||||
setTimeout(bypassRecaptcha, 2000);
|
||||
}
|
||||
|
||||
} catch (e) {
|
||||
log(`Bypass failed: ${e.message}`);
|
||||
}
|
||||
}
|
||||
|
||||
// Create a MutationObserver to watch for reCAPTCHA elements
|
||||
log('Setting up MutationObserver...');
|
||||
const observer = new MutationObserver((mutations) => {
|
||||
mutations.forEach((mutation) => {
|
||||
mutation.addedNodes.forEach((node) => {
|
||||
if (node.nodeType === 1 && // Element node
|
||||
((node.tagName === 'SCRIPT' && node.src && node.src.includes('recaptcha')) ||
|
||||
(node.tagName === 'IFRAME' && node.src && node.src.includes('recaptcha')))) {
|
||||
log(`Detected new reCAPTCHA element: ${node.tagName} - ${node.src}`);
|
||||
bypassRecaptcha();
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
// Start observing
|
||||
observer.observe(document, {
|
||||
childList: true,
|
||||
subtree: true
|
||||
});
|
||||
log('MutationObserver started');
|
||||
|
||||
// Run on page load
|
||||
if (document.readyState === 'loading') {
|
||||
log('Document still loading, waiting for DOMContentLoaded');
|
||||
document.addEventListener('DOMContentLoaded', bypassRecaptcha);
|
||||
} else {
|
||||
log('Document already loaded, starting bypass process');
|
||||
bypassRecaptcha();
|
||||
}
|
||||
@@ -5,7 +5,11 @@ import uuid
|
||||
import hashlib
|
||||
import shutil
|
||||
import sqlite3
|
||||
import platform
|
||||
import re
|
||||
import tempfile
|
||||
from colorama import Fore, Style, init
|
||||
from typing import Tuple
|
||||
|
||||
# 初始化colorama
|
||||
init()
|
||||
@@ -20,6 +24,173 @@ EMOJI = {
|
||||
"RESET": "🔄",
|
||||
}
|
||||
|
||||
def get_cursor_paths(translator=None) -> Tuple[str, str]:
|
||||
"""根据不同操作系统获取 Cursor 相关路径"""
|
||||
system = platform.system()
|
||||
|
||||
paths_map = {
|
||||
"Darwin": {
|
||||
"base": "/Applications/Cursor.app/Contents/Resources/app",
|
||||
"package": "package.json",
|
||||
"main": "out/main.js",
|
||||
},
|
||||
"Windows": {
|
||||
"base": os.path.join(
|
||||
os.getenv("LOCALAPPDATA", ""), "Programs", "Cursor", "resources", "app"
|
||||
),
|
||||
"package": "package.json",
|
||||
"main": "out/main.js",
|
||||
},
|
||||
"Linux": {
|
||||
"bases": ["/opt/Cursor/resources/app", "/usr/share/cursor/resources/app"],
|
||||
"package": "package.json",
|
||||
"main": "out/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"]:
|
||||
pkg_path = os.path.join(base, paths_map["Linux"]["package"])
|
||||
if os.path.exists(pkg_path):
|
||||
return (pkg_path, os.path.join(base, paths_map["Linux"]["main"]))
|
||||
raise OSError(translator.get('reset.linux_path_not_found') if translator else "在 Linux 系统上未找到 Cursor 安装路径")
|
||||
|
||||
base_path = paths_map[system]["base"]
|
||||
return (
|
||||
os.path.join(base_path, paths_map[system]["package"]),
|
||||
os.path.join(base_path, paths_map[system]["main"]),
|
||||
)
|
||||
|
||||
def version_check(version: str, min_version: str = "", max_version: str = "", translator=None) -> bool:
|
||||
"""版本号检查"""
|
||||
version_pattern = r"^\d+\.\d+\.\d+$"
|
||||
try:
|
||||
if not re.match(version_pattern, version):
|
||||
print(f"{Fore.RED}{EMOJI['ERROR']} {translator.get('reset.invalid_version_format', version=version)}{Style.RESET_ALL}")
|
||||
return False
|
||||
|
||||
def parse_version(ver: str) -> Tuple[int, ...]:
|
||||
return tuple(map(int, ver.split(".")))
|
||||
|
||||
current = parse_version(version)
|
||||
|
||||
if min_version and current < parse_version(min_version):
|
||||
print(f"{Fore.RED}{EMOJI['ERROR']} {translator.get('reset.version_too_low', version=version, min_version=min_version)}{Style.RESET_ALL}")
|
||||
return False
|
||||
|
||||
if max_version and current > parse_version(max_version):
|
||||
print(f"{Fore.RED}{EMOJI['ERROR']} {translator.get('reset.version_too_high', version=version, max_version=max_version)}{Style.RESET_ALL}")
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
print(f"{Fore.RED}{EMOJI['ERROR']} {translator.get('reset.version_check_error', error=str(e))}{Style.RESET_ALL}")
|
||||
return False
|
||||
|
||||
def check_cursor_version(translator) -> bool:
|
||||
"""检查 Cursor 版本"""
|
||||
try:
|
||||
pkg_path, _ = get_cursor_paths(translator)
|
||||
with open(pkg_path, "r", encoding="utf-8") as f:
|
||||
version = json.load(f)["version"]
|
||||
return version_check(version, min_version="0.45.0", translator=translator)
|
||||
except Exception as e:
|
||||
print(f"{Fore.RED}{EMOJI['ERROR']} {translator.get('reset.check_version_failed', error=str(e))}{Style.RESET_ALL}")
|
||||
return False
|
||||
|
||||
def modify_main_js(main_path: str, translator) -> bool:
|
||||
"""修改 main.js 文件"""
|
||||
try:
|
||||
original_stat = os.stat(main_path)
|
||||
original_mode = original_stat.st_mode
|
||||
original_uid = original_stat.st_uid
|
||||
original_gid = original_stat.st_gid
|
||||
|
||||
with tempfile.NamedTemporaryFile(mode="w", delete=False) as tmp_file:
|
||||
with open(main_path, "r", encoding="utf-8") as main_file:
|
||||
content = main_file.read()
|
||||
|
||||
patterns = {
|
||||
r"async getMachineId\(\)\{return [^??]+\?\?([^}]+)\}": r"async getMachineId(){return \1}",
|
||||
r"async getMacMachineId\(\)\{return [^??]+\?\?([^}]+)\}": r"async getMacMachineId(){return \1}",
|
||||
}
|
||||
|
||||
for pattern, replacement in patterns.items():
|
||||
content = re.sub(pattern, replacement, content)
|
||||
|
||||
tmp_file.write(content)
|
||||
tmp_path = tmp_file.name
|
||||
|
||||
shutil.copy2(main_path, main_path + ".old")
|
||||
shutil.move(tmp_path, main_path)
|
||||
|
||||
os.chmod(main_path, original_mode)
|
||||
if os.name != "nt":
|
||||
os.chown(main_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():
|
||||
os.unlink(tmp_path)
|
||||
return False
|
||||
|
||||
def patch_cursor_get_machine_id(translator) -> bool:
|
||||
"""修补 Cursor getMachineId 函数"""
|
||||
try:
|
||||
print(f"{Fore.CYAN}{EMOJI['INFO']} {translator.get('reset.start_patching')}...{Style.RESET_ALL}")
|
||||
|
||||
# 获取路径
|
||||
pkg_path, main_path = get_cursor_paths(translator)
|
||||
|
||||
# 检查文件权限
|
||||
for file_path in [pkg_path, main_path]:
|
||||
if not os.path.isfile(file_path):
|
||||
print(f"{Fore.RED}{EMOJI['ERROR']} {translator.get('reset.file_not_found', path=file_path)}{Style.RESET_ALL}")
|
||||
return False
|
||||
if not os.access(file_path, os.W_OK):
|
||||
print(f"{Fore.RED}{EMOJI['ERROR']} {translator.get('reset.no_write_permission', path=file_path)}{Style.RESET_ALL}")
|
||||
return False
|
||||
|
||||
# 获取版本号
|
||||
try:
|
||||
with open(pkg_path, "r", encoding="utf-8") as f:
|
||||
version = json.load(f)["version"]
|
||||
print(f"{Fore.CYAN}{EMOJI['INFO']} {translator.get('reset.current_version', version=version)}{Style.RESET_ALL}")
|
||||
except Exception as e:
|
||||
print(f"{Fore.RED}{EMOJI['ERROR']} {translator.get('reset.read_version_failed', error=str(e))}{Style.RESET_ALL}")
|
||||
return False
|
||||
|
||||
# 检查版本
|
||||
if not version_check(version, min_version="0.45.0", translator=translator):
|
||||
print(f"{Fore.RED}{EMOJI['ERROR']} {translator.get('reset.version_not_supported')}{Style.RESET_ALL}")
|
||||
return False
|
||||
|
||||
print(f"{Fore.CYAN}{EMOJI['INFO']} {translator.get('reset.version_check_passed')}{Style.RESET_ALL}")
|
||||
|
||||
# 备份文件
|
||||
backup_path = main_path + ".bak"
|
||||
if not os.path.exists(backup_path):
|
||||
shutil.copy2(main_path, backup_path)
|
||||
print(f"{Fore.GREEN}{EMOJI['SUCCESS']} {translator.get('reset.backup_created', path=backup_path)}{Style.RESET_ALL}")
|
||||
|
||||
# 修改文件
|
||||
if not modify_main_js(main_path, translator):
|
||||
return False
|
||||
|
||||
print(f"{Fore.GREEN}{EMOJI['SUCCESS']} {translator.get('reset.patch_completed')}{Style.RESET_ALL}")
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
print(f"{Fore.RED}{EMOJI['ERROR']} {translator.get('reset.patch_failed', error=str(e))}{Style.RESET_ALL}")
|
||||
return False
|
||||
|
||||
class MachineIDResetter:
|
||||
def __init__(self, translator=None):
|
||||
self.translator = translator
|
||||
@@ -98,7 +269,7 @@ class MachineIDResetter:
|
||||
INSERT OR REPLACE INTO ItemTable (key, value)
|
||||
VALUES (?, ?)
|
||||
""", (key, value))
|
||||
print(f"{EMOJI['INFO']} {Fore.CYAN}{self.translator.get('reset.updating_pair')}: {key}{Style.RESET_ALL}")
|
||||
print(f"{EMOJI['INFO']} {Fore.CYAN} {self.translator.get('reset.updating_pair')}: {key}{Style.RESET_ALL}")
|
||||
|
||||
conn.commit()
|
||||
conn.close()
|
||||
@@ -109,6 +280,59 @@ class MachineIDResetter:
|
||||
print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('reset.sqlite_error', error=str(e))}{Style.RESET_ALL}")
|
||||
return False
|
||||
|
||||
def update_system_ids(self, new_ids):
|
||||
"""更新系统级别的ID"""
|
||||
try:
|
||||
print(f"{Fore.CYAN}{EMOJI['INFO']} {self.translator.get('reset.updating_system_ids')}...{Style.RESET_ALL}")
|
||||
|
||||
if sys.platform.startswith("win"):
|
||||
self._update_windows_machine_guid()
|
||||
elif sys.platform == "darwin":
|
||||
self._update_macos_platform_uuid(new_ids)
|
||||
|
||||
print(f"{Fore.GREEN}{EMOJI['SUCCESS']} {self.translator.get('reset.system_ids_updated')}{Style.RESET_ALL}")
|
||||
return True
|
||||
except Exception as e:
|
||||
print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('reset.system_ids_update_failed', error=str(e))}{Style.RESET_ALL}")
|
||||
return False
|
||||
|
||||
def _update_windows_machine_guid(self):
|
||||
"""更新Windows MachineGuid"""
|
||||
try:
|
||||
import winreg
|
||||
key = winreg.OpenKey(
|
||||
winreg.HKEY_LOCAL_MACHINE,
|
||||
"SOFTWARE\\Microsoft\\Cryptography",
|
||||
0,
|
||||
winreg.KEY_WRITE | winreg.KEY_WOW64_64KEY
|
||||
)
|
||||
new_guid = str(uuid.uuid4())
|
||||
winreg.SetValueEx(key, "MachineGuid", 0, winreg.REG_SZ, new_guid)
|
||||
winreg.CloseKey(key)
|
||||
print("Windows MachineGuid updated successfully")
|
||||
except PermissionError:
|
||||
print("Permission denied: Run as administrator to update Windows MachineGuid")
|
||||
raise
|
||||
except Exception as e:
|
||||
print(f"Failed to update Windows MachineGuid: {e}")
|
||||
raise
|
||||
|
||||
def _update_macos_platform_uuid(self, new_ids):
|
||||
"""更新macOS Platform UUID"""
|
||||
try:
|
||||
uuid_file = "/var/root/Library/Preferences/SystemConfiguration/com.apple.platform.uuid.plist"
|
||||
if os.path.exists(uuid_file):
|
||||
# 使用sudo来执行plutil命令
|
||||
cmd = f'sudo plutil -replace "UUID" -string "{new_ids["telemetry.macMachineId"]}" "{uuid_file}"'
|
||||
result = os.system(cmd)
|
||||
if result == 0:
|
||||
print("macOS Platform UUID updated successfully")
|
||||
else:
|
||||
raise Exception("Failed to execute plutil command")
|
||||
except Exception as e:
|
||||
print(f"Failed to update macOS Platform UUID: {e}")
|
||||
raise
|
||||
|
||||
def reset_machine_ids(self):
|
||||
"""重置机器ID并备份原文件"""
|
||||
try:
|
||||
@@ -136,14 +360,27 @@ class MachineIDResetter:
|
||||
print(f"{Fore.CYAN}{EMOJI['RESET']} {self.translator.get('reset.generating')}...{Style.RESET_ALL}")
|
||||
new_ids = self.generate_new_ids()
|
||||
|
||||
# 更新配置文件
|
||||
config.update(new_ids)
|
||||
|
||||
print(f"{Fore.CYAN}{EMOJI['FILE']} {self.translator.get('reset.saving_json')}...{Style.RESET_ALL}")
|
||||
with open(self.db_path, "w", encoding="utf-8") as f:
|
||||
json.dump(config, f, indent=4)
|
||||
|
||||
# 更新SQLite数据库
|
||||
self.update_sqlite_db(new_ids)
|
||||
|
||||
# 更新系统ID
|
||||
self.update_system_ids(new_ids)
|
||||
|
||||
# 检查 Cursor 版本并执行相应的操作
|
||||
greater_than_0_45 = check_cursor_version(self.translator)
|
||||
if greater_than_0_45:
|
||||
print(f"{Fore.CYAN}{EMOJI['INFO']} 检测到 Cursor 版本 >= 0.45.0,正在修补 getMachineId...{Style.RESET_ALL}")
|
||||
patch_cursor_get_machine_id(self.translator)
|
||||
else:
|
||||
print(f"{Fore.YELLOW}{EMOJI['INFO']} Cursor 版本 < 0.45.0,跳过 getMachineId 修补{Style.RESET_ALL}")
|
||||
|
||||
print(f"{Fore.GREEN}{EMOJI['SUCCESS']} {self.translator.get('reset.success')}{Style.RESET_ALL}")
|
||||
print(f"\n{Fore.CYAN}{self.translator.get('reset.new_id')}:{Style.RESET_ALL}")
|
||||
for key, value in new_ids.items():
|
||||
@@ -160,18 +397,17 @@ class MachineIDResetter:
|
||||
return False
|
||||
|
||||
def run(translator=None):
|
||||
"""Main function to be called from main.py"""
|
||||
"""便捷函数,用于直接调用重置功能"""
|
||||
print(f"\n{Fore.CYAN}{'='*50}{Style.RESET_ALL}")
|
||||
print(f"{Fore.CYAN}{EMOJI['RESET']} {translator.get('reset.title')}{Style.RESET_ALL}")
|
||||
print(f"{Fore.CYAN}{'='*50}{Style.RESET_ALL}")
|
||||
|
||||
resetter = MachineIDResetter(translator)
|
||||
resetter = MachineIDResetter(translator) # 正確傳遞 translator
|
||||
resetter.reset_machine_ids()
|
||||
|
||||
print(f"\n{Fore.CYAN}{'='*50}{Style.RESET_ALL}")
|
||||
input(f"{EMOJI['INFO']} {translator.get('reset.press_enter')}...")
|
||||
|
||||
if __name__ == "__main__":
|
||||
# 如果直接运行,使用默认翻译器
|
||||
from main import translator as main_translator
|
||||
run(main_translator)
|
||||
Reference in New Issue
Block a user