forked from mirrors/cursor-free-vip
Compare commits
18 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9f51ba8128 | ||
|
|
9aa09c436e | ||
|
|
1e3e9c99eb | ||
|
|
3f9cbc3d08 | ||
|
|
12d46d5f18 | ||
|
|
6cb3ad79af | ||
|
|
6470c65f8b | ||
|
|
491b227486 | ||
|
|
96c0cd5274 | ||
|
|
60a438e618 | ||
|
|
6a25871366 | ||
|
|
b46a58bd23 | ||
|
|
fea2b88a8e | ||
|
|
63fe39f2c1 | ||
|
|
386ffa4568 | ||
|
|
9c66725caf | ||
|
|
16b6ba95e2 | ||
|
|
3424f49a57 |
4
.github/workflows/build.yml
vendored
4
.github/workflows/build.yml
vendored
@@ -6,7 +6,7 @@ on:
|
|||||||
version:
|
version:
|
||||||
description: 'Version number (e.g. 1.0.9)'
|
description: 'Version number (e.g. 1.0.9)'
|
||||||
required: true
|
required: true
|
||||||
default: '1.8.07'
|
default: '1.8.09'
|
||||||
|
|
||||||
permissions:
|
permissions:
|
||||||
contents: write
|
contents: write
|
||||||
@@ -241,4 +241,4 @@ jobs:
|
|||||||
draft: false
|
draft: false
|
||||||
prerelease: false
|
prerelease: false
|
||||||
env:
|
env:
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
26
CHANGELOG.md
26
CHANGELOG.md
@@ -1,5 +1,31 @@
|
|||||||
# Change Log
|
# Change Log
|
||||||
|
|
||||||
|
## v1.8.10
|
||||||
|
1. Add: Check User Authorized | 添加檢查用戶授權
|
||||||
|
2. Fix: Linux Reset Process Error: 'base' | 修復 Linux 重置過程錯誤:'base'
|
||||||
|
3. Updated the get_workbench_cursor_path function to handle Linux systems more effectively. | 更新 get_workbench_cursor_path 函數以更有效地處理 Linux 系統
|
||||||
|
4. Added logic to use the first base path if no valid paths are found in the existing loop. | 添加邏輯以在找不到有效路徑時使用第一個基礎路徑
|
||||||
|
5. Improved maintainability and clarity of the code by explicitly handling different operating systems. | 通過明確處理不同的操作系統,顯著提高了代碼的可維護性和清晰性
|
||||||
|
6. Fix: Some Issues | 修復一些問題
|
||||||
|
|
||||||
|
## v1.8.09
|
||||||
|
1. Add: Bypass Token Limit Check | 繞過 Token 使用限制檢查
|
||||||
|
2. Add:Bypass Claude Limit 30000 set to 900000(9e5) | 繞過 Claude 使用限制 30000 設置為 900000(9e5)
|
||||||
|
3. Add: Force Update Config | 添加強制更新配置
|
||||||
|
4. Add: Multilanguage support for force update | 添加強制更新功能的多語言支持
|
||||||
|
5. Fix: Reset break | 修復重置中斷
|
||||||
|
4. Fix: Some Issues | 修復一些問題
|
||||||
|
|
||||||
|
## v1.8.08
|
||||||
|
1. Add: Force Update Config | 添加強制更新配置
|
||||||
|
2. Add: Multilanguage support for force update | 添加強制更新功能的多語言支持
|
||||||
|
3. Fix: Google Auth & Github Auth JWT Problem | 修復 Google Auth & Github Auth JWT 問題
|
||||||
|
4. Fix: Totally reset import & import * raw options problem | 修復 totally reset import & import * raw 選項問題
|
||||||
|
5. Fix: reset.file_not_found problem | 修復 reset.file_not_found 問題
|
||||||
|
6. Outdated: Bypass Cursor Version Check | 過期:繞過 Cursor 版本檢查
|
||||||
|
7. Document: i.header.set("x-cursor-config-version", "UUID4-xxxxxx-xxxxxx-xxxxxx-xxxxxx"); | 文檔:i.header.set("x-cursor-config-version", "UUID4-xxxxxx-xxxxxx-xxxxxx-xxxxxx");
|
||||||
|
8. Fix: Some Issues | 修復一些問題
|
||||||
|
|
||||||
## v1.8.07
|
## v1.8.07
|
||||||
1. Add: Bypass Cursor Version Check | 添加繞過 Cursor 版本檢查
|
1. Add: Bypass Cursor Version Check | 添加繞過 Cursor 版本檢查
|
||||||
2. Add: Multilanguage support for bypass | 添加繞過的多語言支持
|
2. Add: Multilanguage support for bypass | 添加繞過的多語言支持
|
||||||
|
|||||||
214
check_user_authorized.py
Normal file
214
check_user_authorized.py
Normal file
@@ -0,0 +1,214 @@
|
|||||||
|
import os
|
||||||
|
import requests
|
||||||
|
import time
|
||||||
|
import hashlib
|
||||||
|
import base64
|
||||||
|
import struct
|
||||||
|
from colorama import Fore, Style, init
|
||||||
|
|
||||||
|
# Initialize colorama
|
||||||
|
init()
|
||||||
|
|
||||||
|
# Define emoji constants
|
||||||
|
EMOJI = {
|
||||||
|
"SUCCESS": "✅",
|
||||||
|
"ERROR": "❌",
|
||||||
|
"INFO": "ℹ️",
|
||||||
|
"WARNING": "⚠️",
|
||||||
|
"KEY": "🔑",
|
||||||
|
"CHECK": "🔍"
|
||||||
|
}
|
||||||
|
|
||||||
|
def generate_hashed64_hex(input_str: str, salt: str = '') -> str:
|
||||||
|
"""Generate a SHA-256 hash of input + salt and return as hex"""
|
||||||
|
hash_obj = hashlib.sha256()
|
||||||
|
hash_obj.update((input_str + salt).encode('utf-8'))
|
||||||
|
return hash_obj.hexdigest()
|
||||||
|
|
||||||
|
def obfuscate_bytes(byte_array: bytearray) -> bytearray:
|
||||||
|
"""Obfuscate bytes using the algorithm from utils.js"""
|
||||||
|
t = 165
|
||||||
|
for r in range(len(byte_array)):
|
||||||
|
byte_array[r] = ((byte_array[r] ^ t) + (r % 256)) & 0xFF
|
||||||
|
t = byte_array[r]
|
||||||
|
return byte_array
|
||||||
|
|
||||||
|
def generate_cursor_checksum(token: str, translator=None) -> str:
|
||||||
|
"""Generate Cursor checksum from token using the algorithm"""
|
||||||
|
try:
|
||||||
|
# Clean the token
|
||||||
|
clean_token = token.strip()
|
||||||
|
|
||||||
|
# Generate machineId and macMachineId
|
||||||
|
machine_id = generate_hashed64_hex(clean_token, 'machineId')
|
||||||
|
mac_machine_id = generate_hashed64_hex(clean_token, 'macMachineId')
|
||||||
|
|
||||||
|
# Get timestamp and convert to byte array
|
||||||
|
timestamp = int(time.time() * 1000) // 1000000
|
||||||
|
byte_array = bytearray(struct.pack('>Q', timestamp)[-6:]) # Take last 6 bytes
|
||||||
|
|
||||||
|
# Obfuscate bytes and encode as base64
|
||||||
|
obfuscated_bytes = obfuscate_bytes(byte_array)
|
||||||
|
encoded_checksum = base64.b64encode(obfuscated_bytes).decode('utf-8')
|
||||||
|
|
||||||
|
# Combine final checksum
|
||||||
|
return f"{encoded_checksum}{machine_id}/{mac_machine_id}"
|
||||||
|
except Exception as e:
|
||||||
|
print(f"{Fore.RED}{EMOJI['ERROR']} {translator.get('auth_check.error_generating_checksum', error=str(e)) if translator else f'Error generating checksum: {str(e)}'}{Style.RESET_ALL}")
|
||||||
|
return ""
|
||||||
|
|
||||||
|
def check_user_authorized(token: str, translator=None) -> bool:
|
||||||
|
"""
|
||||||
|
Check if the user is authorized with the given token
|
||||||
|
|
||||||
|
Args:
|
||||||
|
token (str): The authorization token
|
||||||
|
translator: Optional translator for internationalization
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
bool: True if authorized, False otherwise
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
print(f"{Fore.CYAN}{EMOJI['CHECK']} {translator.get('auth_check.checking_authorization') if translator else 'Checking authorization...'}{Style.RESET_ALL}")
|
||||||
|
|
||||||
|
# Clean the token
|
||||||
|
if token and '%3A%3A' in token:
|
||||||
|
token = token.split('%3A%3A')[1]
|
||||||
|
elif token and '::' in token:
|
||||||
|
token = token.split('::')[1]
|
||||||
|
|
||||||
|
# Remove any whitespace
|
||||||
|
token = token.strip()
|
||||||
|
|
||||||
|
if not token or len(token) < 10: # Add a basic validation for token length
|
||||||
|
print(f"{Fore.RED}{EMOJI['ERROR']} {translator.get('auth_check.invalid_token') if translator else 'Invalid token'}{Style.RESET_ALL}")
|
||||||
|
return False
|
||||||
|
|
||||||
|
print(f"{Fore.CYAN}{EMOJI['INFO']} {translator.get('auth_check.token_length', length=len(token)) if translator else f'Token length: {len(token)} characters'}{Style.RESET_ALL}")
|
||||||
|
|
||||||
|
# Try to get usage info using the DashboardService API
|
||||||
|
try:
|
||||||
|
# Generate checksum
|
||||||
|
checksum = generate_cursor_checksum(token, translator)
|
||||||
|
|
||||||
|
# Create request headers
|
||||||
|
headers = {
|
||||||
|
'accept-encoding': 'gzip',
|
||||||
|
'authorization': f'Bearer {token}',
|
||||||
|
'connect-protocol-version': '1',
|
||||||
|
'content-type': 'application/proto',
|
||||||
|
'user-agent': 'connect-es/1.6.1',
|
||||||
|
'x-cursor-checksum': checksum,
|
||||||
|
'x-cursor-client-version': '0.48.7',
|
||||||
|
'x-cursor-timezone': 'Asia/Shanghai',
|
||||||
|
'x-ghost-mode': 'false',
|
||||||
|
'Host': 'api2.cursor.sh'
|
||||||
|
}
|
||||||
|
|
||||||
|
print(f"{Fore.CYAN}{EMOJI['INFO']} {translator.get('auth_check.checking_usage_information') if translator else 'Checking usage information...'}{Style.RESET_ALL}")
|
||||||
|
|
||||||
|
# Make the request - this endpoint doesn't need a request body
|
||||||
|
usage_response = requests.post(
|
||||||
|
'https://api2.cursor.sh/aiserver.v1.DashboardService/GetUsageBasedPremiumRequests',
|
||||||
|
headers=headers,
|
||||||
|
data=b'', # Empty body
|
||||||
|
timeout=10
|
||||||
|
)
|
||||||
|
|
||||||
|
print(f"{Fore.CYAN}{EMOJI['INFO']} {translator.get('auth_check.usage_response', response=usage_response.status_code) if translator else f'Usage response status: {usage_response.status_code}'}{Style.RESET_ALL}")
|
||||||
|
|
||||||
|
if usage_response.status_code == 200:
|
||||||
|
print(f"{Fore.GREEN}{EMOJI['SUCCESS']} {translator.get('auth_check.user_authorized') if translator else 'User is authorized'}{Style.RESET_ALL}")
|
||||||
|
return True
|
||||||
|
elif usage_response.status_code == 401 or usage_response.status_code == 403:
|
||||||
|
print(f"{Fore.RED}{EMOJI['ERROR']} {translator.get('auth_check.user_unauthorized') if translator else 'User is unauthorized'}{Style.RESET_ALL}")
|
||||||
|
return False
|
||||||
|
else:
|
||||||
|
print(f"{Fore.YELLOW}{EMOJI['WARNING']} {translator.get('auth_check.unexpected_status_code', code=usage_response.status_code) if translator else f'Unexpected status code: {usage_response.status_code}'}{Style.RESET_ALL}")
|
||||||
|
|
||||||
|
# If the token at least looks like a valid JWT, consider it valid
|
||||||
|
if token.startswith('eyJ') and '.' in token and len(token) > 100:
|
||||||
|
print(f"{Fore.YELLOW}{EMOJI['WARNING']} {translator.get('auth_check.jwt_token_warning') if translator else 'Token appears to be in JWT format, but API check returned an unexpected status code. The token might be valid but API access is restricted.'}{Style.RESET_ALL}")
|
||||||
|
return True
|
||||||
|
|
||||||
|
return False
|
||||||
|
except Exception as e:
|
||||||
|
print(f"{Fore.YELLOW}{EMOJI['WARNING']} Error checking usage: {str(e)}{Style.RESET_ALL}")
|
||||||
|
|
||||||
|
# If the token at least looks like a valid JWT, consider it valid even if the API check fails
|
||||||
|
if token.startswith('eyJ') and '.' in token and len(token) > 100:
|
||||||
|
print(f"{Fore.YELLOW}{EMOJI['WARNING']} {translator.get('auth_check.jwt_token_warning') if translator else 'Token appears to be in JWT format, but API check failed. The token might be valid but API access is restricted.'}{Style.RESET_ALL}")
|
||||||
|
return True
|
||||||
|
|
||||||
|
return False
|
||||||
|
|
||||||
|
except requests.exceptions.Timeout:
|
||||||
|
print(f"{Fore.RED}{EMOJI['ERROR']} {translator.get('auth_check.request_timeout') if translator else 'Request timed out'}{Style.RESET_ALL}")
|
||||||
|
return False
|
||||||
|
except requests.exceptions.ConnectionError:
|
||||||
|
print(f"{Fore.RED}{EMOJI['ERROR']} {translator.get('auth_check.connection_error') if translator else 'Connection error'}{Style.RESET_ALL}")
|
||||||
|
return False
|
||||||
|
except Exception as e:
|
||||||
|
print(f"{Fore.RED}{EMOJI['ERROR']} {translator.get('auth_check.check_error', error=str(e)) if translator else f'Error checking authorization: {str(e)}'}{Style.RESET_ALL}")
|
||||||
|
return False
|
||||||
|
|
||||||
|
def run(translator=None):
|
||||||
|
"""Run function to be called from main.py"""
|
||||||
|
try:
|
||||||
|
# Ask user if they want to get token from database or input manually
|
||||||
|
choice = input(f"{Fore.CYAN}{EMOJI['INFO']} {translator.get('auth_check.token_source') if translator else 'Get token from database or input manually? (d/m, default: d): '}{Style.RESET_ALL}").strip().lower()
|
||||||
|
|
||||||
|
token = None
|
||||||
|
|
||||||
|
# If user chooses database or default
|
||||||
|
if not choice or choice == 'd':
|
||||||
|
print(f"{Fore.CYAN}{EMOJI['INFO']} {translator.get('auth_check.getting_token_from_db') if translator else 'Getting token from database...'}{Style.RESET_ALL}")
|
||||||
|
|
||||||
|
try:
|
||||||
|
# Import functions from cursor_acc_info.py
|
||||||
|
from cursor_acc_info import get_token
|
||||||
|
|
||||||
|
# Get token using the get_token function
|
||||||
|
token = get_token()
|
||||||
|
|
||||||
|
if token:
|
||||||
|
print(f"{Fore.GREEN}{EMOJI['SUCCESS']} {translator.get('auth_check.token_found_in_db') if translator else 'Token found in database'}{Style.RESET_ALL}")
|
||||||
|
else:
|
||||||
|
print(f"{Fore.YELLOW}{EMOJI['WARNING']} {translator.get('auth_check.token_not_found_in_db') if translator else 'Token not found in database'}{Style.RESET_ALL}")
|
||||||
|
except ImportError:
|
||||||
|
print(f"{Fore.YELLOW}{EMOJI['WARNING']} {translator.get('auth_check.cursor_acc_info_not_found') if translator else 'cursor_acc_info.py not found'}{Style.RESET_ALL}")
|
||||||
|
except Exception as e:
|
||||||
|
print(f"{Fore.YELLOW}{EMOJI['WARNING']} {translator.get('auth_check.error_getting_token_from_db', error=str(e)) if translator else f'Error getting token from database: {str(e)}'}{Style.RESET_ALL}")
|
||||||
|
|
||||||
|
# If token not found in database or user chooses manual input
|
||||||
|
if not token:
|
||||||
|
# Try to get token from environment
|
||||||
|
token = os.environ.get('CURSOR_TOKEN')
|
||||||
|
|
||||||
|
# If not in environment, ask user to input
|
||||||
|
if not token:
|
||||||
|
token = input(f"{Fore.CYAN}{EMOJI['KEY']} {translator.get('auth_check.enter_token') if translator else 'Enter your Cursor token: '}{Style.RESET_ALL}")
|
||||||
|
|
||||||
|
# Check authorization
|
||||||
|
is_authorized = check_user_authorized(token, translator)
|
||||||
|
|
||||||
|
if is_authorized:
|
||||||
|
print(f"{Fore.GREEN}{EMOJI['SUCCESS']} {translator.get('auth_check.authorization_successful') if translator else 'Authorization successful!'}{Style.RESET_ALL}")
|
||||||
|
else:
|
||||||
|
print(f"{Fore.RED}{EMOJI['ERROR']} {translator.get('auth_check.authorization_failed') if translator else 'Authorization failed!'}{Style.RESET_ALL}")
|
||||||
|
|
||||||
|
return is_authorized
|
||||||
|
|
||||||
|
except KeyboardInterrupt:
|
||||||
|
print(f"\n{Fore.YELLOW}{EMOJI['WARNING']} {translator.get('auth_check.operation_cancelled') if translator else 'Operation cancelled by user'}{Style.RESET_ALL}")
|
||||||
|
return False
|
||||||
|
except Exception as e:
|
||||||
|
print(f"{Fore.RED}{EMOJI['ERROR']} {translator.get('auth_check.unexpected_error', error=str(e)) if translator else f'Unexpected error: {str(e)}'}{Style.RESET_ALL}")
|
||||||
|
return False
|
||||||
|
|
||||||
|
def main(translator=None):
|
||||||
|
"""Main function to check user authorization"""
|
||||||
|
return run(translator)
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
53
config.py
53
config.py
@@ -3,6 +3,8 @@ import sys
|
|||||||
import configparser
|
import configparser
|
||||||
from colorama import Fore, Style
|
from colorama import Fore, Style
|
||||||
from utils import get_user_documents_path, get_default_chrome_path, get_linux_cursor_path
|
from utils import get_user_documents_path, get_default_chrome_path, get_linux_cursor_path
|
||||||
|
import shutil
|
||||||
|
import datetime
|
||||||
|
|
||||||
EMOJI = {
|
EMOJI = {
|
||||||
"INFO": "ℹ️",
|
"INFO": "ℹ️",
|
||||||
@@ -52,6 +54,7 @@ def setup_config(translator=None):
|
|||||||
},
|
},
|
||||||
'Utils': {
|
'Utils': {
|
||||||
'enabled_update_check': 'True',
|
'enabled_update_check': 'True',
|
||||||
|
'enabled_force_update': 'False',
|
||||||
'enabled_account_info': 'True'
|
'enabled_account_info': 'True'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -257,6 +260,56 @@ def print_config(config, translator=None):
|
|||||||
|
|
||||||
print()
|
print()
|
||||||
|
|
||||||
|
def force_update_config(translator=None):
|
||||||
|
"""
|
||||||
|
Force update configuration file with latest defaults if update check is enabled.
|
||||||
|
Args:
|
||||||
|
translator: Translator instance
|
||||||
|
Returns:
|
||||||
|
ConfigParser instance or None if failed
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
config_dir = os.path.join(get_user_documents_path(), ".cursor-free-vip")
|
||||||
|
config_file = os.path.join(config_dir, "config.ini")
|
||||||
|
current_time = datetime.datetime.now()
|
||||||
|
|
||||||
|
# If the config file exists, check if forced update is enabled
|
||||||
|
if os.path.exists(config_file):
|
||||||
|
# First, read the existing configuration
|
||||||
|
existing_config = configparser.ConfigParser()
|
||||||
|
existing_config.read(config_file, encoding='utf-8')
|
||||||
|
# Check if "enabled_update_check" is True
|
||||||
|
update_enabled = True # Default to True if not set
|
||||||
|
if existing_config.has_section('Utils') and existing_config.has_option('Utils', 'enabled_force_update'):
|
||||||
|
update_enabled = existing_config.get('Utils', 'enabled_force_update').strip().lower() in ('true', 'yes', '1', 'on')
|
||||||
|
|
||||||
|
if update_enabled:
|
||||||
|
try:
|
||||||
|
# Create a backup
|
||||||
|
backup_file = f"{config_file}.bak.{current_time.strftime('%Y%m%d_%H%M%S')}"
|
||||||
|
shutil.copy2(config_file, backup_file)
|
||||||
|
if translator:
|
||||||
|
print(f"\n{Fore.CYAN}{EMOJI['INFO']} {translator.get('config.backup_created', path=backup_file) if translator else f'Backup created: {backup_file}'}{Style.RESET_ALL}")
|
||||||
|
print(f"\n{Fore.CYAN}{EMOJI['INFO']} {translator.get('config.config_force_update_enabled') if translator else 'Config file force update enabled'}{Style.RESET_ALL}")
|
||||||
|
# Delete the original config file (forced update)
|
||||||
|
os.remove(config_file)
|
||||||
|
if translator:
|
||||||
|
print(f"{Fore.CYAN}{EMOJI['INFO']} {translator.get('config.config_removed') if translator else 'Config file removed for forced update'}{Style.RESET_ALL}")
|
||||||
|
except Exception as e:
|
||||||
|
if translator:
|
||||||
|
print(f"{Fore.RED}{EMOJI['ERROR']} {translator.get('config.backup_failed', error=str(e)) if translator else f'Failed to backup config: {str(e)}'}{Style.RESET_ALL}")
|
||||||
|
else:
|
||||||
|
if translator:
|
||||||
|
print(f"\n{Fore.CYAN}{EMOJI['INFO']} {translator.get('config.config_force_update_disabled', fallback='Config file force update disabled by configuration. Keeping existing config file.') if translator else 'Config file force update disabled by configuration. Keeping existing config file.'}{Style.RESET_ALL}")
|
||||||
|
|
||||||
|
# Generate a new (or updated) configuration if needed
|
||||||
|
return setup_config(translator)
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
if translator:
|
||||||
|
print(f"{Fore.RED}{EMOJI['ERROR']} {translator.get('config.force_update_failed', error=str(e)) if translator else f'Force update config failed: {str(e)}'}{Style.RESET_ALL}")
|
||||||
|
return None
|
||||||
|
|
||||||
def get_config(translator=None):
|
def get_config(translator=None):
|
||||||
"""Get existing config or create new one"""
|
"""Get existing config or create new one"""
|
||||||
return setup_config(translator)
|
return setup_config(translator)
|
||||||
@@ -30,7 +30,8 @@
|
|||||||
"continue_prompt": "Continue? (y/N): ",
|
"continue_prompt": "Continue? (y/N): ",
|
||||||
"operation_cancelled_by_user": "Operation cancelled by user",
|
"operation_cancelled_by_user": "Operation cancelled by user",
|
||||||
"exiting": "Exiting ……",
|
"exiting": "Exiting ……",
|
||||||
"bypass_version_check": "Bypass Cursor Version Check"
|
"bypass_version_check": "Bypass Cursor Version Check",
|
||||||
|
"check_user_authorized": "Check User Authorized"
|
||||||
},
|
},
|
||||||
"languages": {
|
"languages": {
|
||||||
"en": "English",
|
"en": "English",
|
||||||
@@ -117,7 +118,8 @@
|
|||||||
"modify_file_failed": "Modify File Failed: {error}",
|
"modify_file_failed": "Modify File Failed: {error}",
|
||||||
"windows_machine_id_updated": "Windows Machine ID Updated Successfully",
|
"windows_machine_id_updated": "Windows Machine ID Updated Successfully",
|
||||||
"update_windows_machine_id_failed": "Update Windows Machine ID Failed: {error}",
|
"update_windows_machine_id_failed": "Update Windows Machine ID Failed: {error}",
|
||||||
"update_windows_machine_guid_failed": "Update Windows Machine GUID Failed: {error}"
|
"update_windows_machine_guid_failed": "Update Windows Machine GUID Failed: {error}",
|
||||||
|
"file_not_found": "File Not Found: {path}"
|
||||||
},
|
},
|
||||||
"register": {
|
"register": {
|
||||||
"title": "Cursor Registration Tool",
|
"title": "Cursor Registration Tool",
|
||||||
@@ -555,7 +557,13 @@
|
|||||||
"config_setup_error": "Error setting up config: {error}",
|
"config_setup_error": "Error setting up config: {error}",
|
||||||
"storage_file_is_valid_and_contains_data": "Storage file is valid and contains data",
|
"storage_file_is_valid_and_contains_data": "Storage file is valid and contains data",
|
||||||
"error_reading_storage_file": "Error reading storage file: {error}",
|
"error_reading_storage_file": "Error reading storage file: {error}",
|
||||||
"also_checked": "Also checked {path}"
|
"also_checked": "Also checked {path}",
|
||||||
|
"backup_created": "Backup created: {path}",
|
||||||
|
"config_removed": "Config file removed for forced update",
|
||||||
|
"backup_failed": "Failed to backup config: {error}",
|
||||||
|
"force_update_failed": "Force update config failed: {error}",
|
||||||
|
"config_force_update_disabled": "Config file force update disabled , skipping forced update",
|
||||||
|
"config_force_update_enabled": "Config file force update enabled , performing forced update"
|
||||||
},
|
},
|
||||||
"oauth": {
|
"oauth": {
|
||||||
"authentication_button_not_found": "Authentication button not found",
|
"authentication_button_not_found": "Authentication button not found",
|
||||||
@@ -691,5 +699,33 @@
|
|||||||
"title": "Cursor Version Bypass Tool",
|
"title": "Cursor Version Bypass Tool",
|
||||||
"description": "This tool modifies Cursor's product.json to bypass version restrictions",
|
"description": "This tool modifies Cursor's product.json to bypass version restrictions",
|
||||||
"menu_option": "Bypass Cursor Version Check"
|
"menu_option": "Bypass Cursor Version Check"
|
||||||
|
},
|
||||||
|
"auth_check": {
|
||||||
|
"checking_authorization": "Checking authorization...",
|
||||||
|
"token_source": "Get token from database or input manually? (d/m, default: d)",
|
||||||
|
"getting_token_from_db": "Getting token from database...",
|
||||||
|
"token_found_in_db": "Token found in database",
|
||||||
|
"token_not_found_in_db": "Token not found in database",
|
||||||
|
"cursor_acc_info_not_found": "cursor_acc_info.py not found",
|
||||||
|
"error_getting_token_from_db": "Error getting token from database: {error}",
|
||||||
|
"enter_token": "Enter your Cursor token: ",
|
||||||
|
"token_length": "Token length: {length} characters",
|
||||||
|
"usage_response_status": "Usage response status: {response}",
|
||||||
|
"unexpected_status_code": "Unexpected status code: {code}",
|
||||||
|
"jwt_token_warning": "Token appears to be in JWT format, but API check returned an unexpected status code. The token might be valid but API access is restricted.",
|
||||||
|
"invalid_token": "Invalid token",
|
||||||
|
"user_authorized": "User is authorized",
|
||||||
|
"user_unauthorized": "User is unauthorized",
|
||||||
|
"request_timeout": "Request timed out",
|
||||||
|
"connection_error": "Connection error",
|
||||||
|
"check_error": "Error checking authorization: {error}",
|
||||||
|
"authorization_successful": "Authorization successful!",
|
||||||
|
"authorization_failed": "Authorization failed!",
|
||||||
|
"operation_cancelled": "Operation cancelled by user",
|
||||||
|
"unexpected_error": "Unexpected error: {error}",
|
||||||
|
"error_generating_checksum": "Error generating checksum: {error}",
|
||||||
|
"checking_usage_information": "Checking usage information...",
|
||||||
|
"check_usage_response": "Check usage response: {response}",
|
||||||
|
"usage_response": "Usage response: {response}"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -30,7 +30,8 @@
|
|||||||
"continue_prompt": "继续?(y/N): ",
|
"continue_prompt": "继续?(y/N): ",
|
||||||
"operation_cancelled_by_user": "操作被用户取消",
|
"operation_cancelled_by_user": "操作被用户取消",
|
||||||
"exiting": "退出中 ……",
|
"exiting": "退出中 ……",
|
||||||
"bypass_version_check": "绕过 Cursor 版本检查"
|
"bypass_version_check": "绕过 Cursor 版本检查",
|
||||||
|
"check_user_authorized": "检查用户授权"
|
||||||
},
|
},
|
||||||
"languages": {
|
"languages": {
|
||||||
"en": "英语",
|
"en": "英语",
|
||||||
@@ -117,7 +118,8 @@
|
|||||||
"modify_file_failed": "修改文件失败: {error}",
|
"modify_file_failed": "修改文件失败: {error}",
|
||||||
"windows_machine_id_updated": "Windows机器ID更新成功",
|
"windows_machine_id_updated": "Windows机器ID更新成功",
|
||||||
"update_windows_machine_id_failed": "更新Windows机器ID失败: {error}",
|
"update_windows_machine_id_failed": "更新Windows机器ID失败: {error}",
|
||||||
"update_windows_machine_guid_failed": "更新Windows机器GUID失败: {error}"
|
"update_windows_machine_guid_failed": "更新Windows机器GUID失败: {error}",
|
||||||
|
"file_not_found": "文件未找到: {path}"
|
||||||
},
|
},
|
||||||
"register": {
|
"register": {
|
||||||
"title": "Cursor 注册工具",
|
"title": "Cursor 注册工具",
|
||||||
@@ -533,7 +535,13 @@
|
|||||||
"config_setup_error": "配置设置错误",
|
"config_setup_error": "配置设置错误",
|
||||||
"storage_file_is_valid_and_contains_data": "存储文件有效且包含数据",
|
"storage_file_is_valid_and_contains_data": "存储文件有效且包含数据",
|
||||||
"error_reading_storage_file": "读取存储文件时出错",
|
"error_reading_storage_file": "读取存储文件时出错",
|
||||||
"also_checked": "也检查了 {path}"
|
"also_checked": "也检查了 {path}",
|
||||||
|
"backup_created": "备份创建: {path}",
|
||||||
|
"config_removed": "配置文件已删除用于强制更新",
|
||||||
|
"backup_failed": "备份失败: {error}",
|
||||||
|
"force_update_failed": "强制更新配置失败: {error}",
|
||||||
|
"config_force_update_disabled": "配置文件强制更新已禁用,跳过强制更新",
|
||||||
|
"config_force_update_enabled": "配置文件强制更新已启用,正在执行强制更新"
|
||||||
},
|
},
|
||||||
"oauth": {
|
"oauth": {
|
||||||
"authentication_button_not_found": "未找到认证按钮",
|
"authentication_button_not_found": "未找到认证按钮",
|
||||||
@@ -669,5 +677,33 @@
|
|||||||
"title": "Cursor 版本绕过工具",
|
"title": "Cursor 版本绕过工具",
|
||||||
"description": "此工具修改 Cursor 的 product.json 以绕过版本限制",
|
"description": "此工具修改 Cursor 的 product.json 以绕过版本限制",
|
||||||
"menu_option": "绕过 Cursor 版本检查"
|
"menu_option": "绕过 Cursor 版本检查"
|
||||||
|
},
|
||||||
|
"auth_check": {
|
||||||
|
"checking_authorization": "检查授权...",
|
||||||
|
"token_source": "从数据库获取 token 或手动输入?(d/m, 默认: d)",
|
||||||
|
"getting_token_from_db": "从数据库获取 token...",
|
||||||
|
"token_found_in_db": "在数据库中找到 token",
|
||||||
|
"token_not_found_in_db": "在数据库中未找到 token",
|
||||||
|
"cursor_acc_info_not_found": "cursor_acc_info.py 未找到",
|
||||||
|
"error_getting_token_from_db": "从数据库获取 token 时出错: {error}",
|
||||||
|
"enter_token": "请输入您的 Cursor token: ",
|
||||||
|
"token_length": "token 长度: {length}",
|
||||||
|
"usage_response_status": "使用情况响应状态: {response}",
|
||||||
|
"unexpected_status_code": "意外状态码: {code}",
|
||||||
|
"jwt_token_warning": "token 似乎是 JWT 格式,但 API 检查返回意外状态码。token 可能有效但 API 访问受限。",
|
||||||
|
"invalid_token": "无效的 token",
|
||||||
|
"user_authorized": "用户已授权",
|
||||||
|
"user_unauthorized": "用户未授权",
|
||||||
|
"request_timeout": "请求超时",
|
||||||
|
"connection_error": "连接错误",
|
||||||
|
"check_error": "检查授权时出错: {error}",
|
||||||
|
"authorization_successful": "授权成功",
|
||||||
|
"authorization_failed": "授权失败",
|
||||||
|
"operation_cancelled": "操作已取消",
|
||||||
|
"unexpected_error": "意外错误: {error}",
|
||||||
|
"error_generating_checksum": "生成校验和时出错: {error}",
|
||||||
|
"checking_usage_information": "检查使用情况...",
|
||||||
|
"check_usage_response": "检查使用情况响应: {response}",
|
||||||
|
"usage_response": "使用情况响应: {response}"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -30,7 +30,8 @@
|
|||||||
"continue_prompt": "繼續?(y/N): ",
|
"continue_prompt": "繼續?(y/N): ",
|
||||||
"operation_cancelled_by_user": "操作被使用者取消",
|
"operation_cancelled_by_user": "操作被使用者取消",
|
||||||
"exiting": "退出中 ……",
|
"exiting": "退出中 ……",
|
||||||
"bypass_version_check": "繞過 Cursor 版本檢查"
|
"bypass_version_check": "繞過 Cursor 版本檢查",
|
||||||
|
"check_user_authorized": "檢查用戶授權"
|
||||||
},
|
},
|
||||||
"languages": {
|
"languages": {
|
||||||
"en": "英文",
|
"en": "英文",
|
||||||
@@ -117,7 +118,8 @@
|
|||||||
"modify_file_failed": "修改文件失敗: {error}",
|
"modify_file_failed": "修改文件失敗: {error}",
|
||||||
"windows_machine_id_updated": "Windows機器ID更新成功",
|
"windows_machine_id_updated": "Windows機器ID更新成功",
|
||||||
"update_windows_machine_id_failed": "更新Windows機器ID失敗: {error}",
|
"update_windows_machine_id_failed": "更新Windows機器ID失敗: {error}",
|
||||||
"update_windows_machine_guid_failed": "更新Windows機器GUID失敗: {error}"
|
"update_windows_machine_guid_failed": "更新Windows機器GUID失敗: {error}",
|
||||||
|
"file_not_found": "文件未找到: {path}"
|
||||||
},
|
},
|
||||||
|
|
||||||
"register": {
|
"register": {
|
||||||
@@ -515,7 +517,13 @@
|
|||||||
"config_setup_error": "配置設置錯誤",
|
"config_setup_error": "配置設置錯誤",
|
||||||
"storage_file_is_valid_and_contains_data": "儲存文件有效且包含數據",
|
"storage_file_is_valid_and_contains_data": "儲存文件有效且包含數據",
|
||||||
"error_reading_storage_file": "讀取儲存文件時出錯",
|
"error_reading_storage_file": "讀取儲存文件時出錯",
|
||||||
"also_checked": "也檢查了 {path}"
|
"also_checked": "也檢查了 {path}",
|
||||||
|
"backup_created": "備份已創建: {path}",
|
||||||
|
"config_removed": "配置文件已刪除用於強制更新",
|
||||||
|
"backup_failed": "備份失敗: {error}",
|
||||||
|
"force_update_failed": "強制更新配置失敗: {error}",
|
||||||
|
"config_force_update_disabled": "配置文件強制更新已禁用,跳過強制更新",
|
||||||
|
"config_force_update_enabled": "配置文件強制更新已啟用,正在執行強制更新"
|
||||||
},
|
},
|
||||||
"oauth": {
|
"oauth": {
|
||||||
"authentication_button_not_found": "未找到認證按鈕",
|
"authentication_button_not_found": "未找到認證按鈕",
|
||||||
@@ -651,5 +659,33 @@
|
|||||||
"title": "Cursor 版本繞過工具",
|
"title": "Cursor 版本繞過工具",
|
||||||
"description": "此工具修改 Cursor 的 product.json 以繞過版本限制",
|
"description": "此工具修改 Cursor 的 product.json 以繞過版本限制",
|
||||||
"menu_option": "繞過 Cursor 版本檢查"
|
"menu_option": "繞過 Cursor 版本檢查"
|
||||||
|
},
|
||||||
|
"auth_check": {
|
||||||
|
"checking_authorization": "檢查授權...",
|
||||||
|
"token_source": "從資料庫獲取 token 或手動輸入?(d/m, 預設: d)",
|
||||||
|
"getting_token_from_db": "從資料庫獲取 token...",
|
||||||
|
"token_found_in_db": "在資料庫中找到 token",
|
||||||
|
"token_not_found_in_db": "在資料庫中未找到 token",
|
||||||
|
"cursor_acc_info_not_found": "cursor_acc_info.py 未找到",
|
||||||
|
"usage_response_status": "使用情況響應狀態: {response}",
|
||||||
|
"unexpected_status_code": "意外狀態碼: {code}",
|
||||||
|
"jwt_token_warning": "token 似乎是 JWT 格式,但 API 檢查返回意外狀態碼。token 可能有效但 API 訪問受限。",
|
||||||
|
"error_getting_token_from_db": "從資料庫獲取 token 時出錯: {error}",
|
||||||
|
"enter_token": "請輸入您的 Cursor token: ",
|
||||||
|
"token_length": "token 長度: {length}",
|
||||||
|
"invalid_token": "無效的 token",
|
||||||
|
"user_authorized": "用戶已授權",
|
||||||
|
"user_unauthorized": "用戶未授權",
|
||||||
|
"request_timeout": "請求超時",
|
||||||
|
"connection_error": "連接錯誤",
|
||||||
|
"check_error": "檢查授權時出錯: {error}",
|
||||||
|
"authorization_successful": "授權成功",
|
||||||
|
"authorization_failed": "授權失敗",
|
||||||
|
"operation_cancelled": "操作已取消",
|
||||||
|
"unexpected_error": "意外錯誤: {error}",
|
||||||
|
"error_generating_checksum": "生成校驗和時出錯: {error}",
|
||||||
|
"checking_usage_information": "檢查使用情況...",
|
||||||
|
"check_usage_response": "檢查使用情況響應: {response}",
|
||||||
|
"usage_response": "使用情況響應: {response}"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
18
main.py
18
main.py
@@ -9,7 +9,7 @@ import locale
|
|||||||
import platform
|
import platform
|
||||||
import requests
|
import requests
|
||||||
import subprocess
|
import subprocess
|
||||||
from config import get_config
|
from config import get_config, force_update_config
|
||||||
import shutil
|
import shutil
|
||||||
import re
|
import re
|
||||||
|
|
||||||
@@ -275,8 +275,8 @@ def print_menu():
|
|||||||
0: f"{Fore.GREEN}0{Style.RESET_ALL}. {EMOJI['ERROR']} {translator.get('menu.exit')}",
|
0: f"{Fore.GREEN}0{Style.RESET_ALL}. {EMOJI['ERROR']} {translator.get('menu.exit')}",
|
||||||
1: f"{Fore.GREEN}1{Style.RESET_ALL}. {EMOJI['RESET']} {translator.get('menu.reset')}",
|
1: f"{Fore.GREEN}1{Style.RESET_ALL}. {EMOJI['RESET']} {translator.get('menu.reset')}",
|
||||||
2: f"{Fore.GREEN}2{Style.RESET_ALL}. {EMOJI['SUCCESS']} {translator.get('menu.register')} ({Fore.RED}{translator.get('menu.outdate')}{Style.RESET_ALL})",
|
2: f"{Fore.GREEN}2{Style.RESET_ALL}. {EMOJI['SUCCESS']} {translator.get('menu.register')} ({Fore.RED}{translator.get('menu.outdate')}{Style.RESET_ALL})",
|
||||||
3: f"{Fore.GREEN}3{Style.RESET_ALL}. {EMOJI['SUN']} {translator.get('menu.register_google')} {EMOJI['ROCKET']} ({Fore.YELLOW}{translator.get('menu.lifetime_access_enabled')} ({Fore.RED}{translator.get('menu.outdate')}{Style.RESET_ALL}))",
|
3: f"{Fore.GREEN}3{Style.RESET_ALL}. {EMOJI['SUN']} {translator.get('menu.register_google')} {EMOJI['ROCKET']} ({Fore.YELLOW}{translator.get('menu.lifetime_access_enabled')}{Style.RESET_ALL})",
|
||||||
4: f"{Fore.GREEN}4{Style.RESET_ALL}. {EMOJI['STAR']} {translator.get('menu.register_github')} {EMOJI['ROCKET']} ({Fore.YELLOW}{translator.get('menu.lifetime_access_enabled')} ({Fore.RED}{translator.get('menu.outdate')}{Style.RESET_ALL}))",
|
4: f"{Fore.GREEN}4{Style.RESET_ALL}. {EMOJI['STAR']} {translator.get('menu.register_github')} {EMOJI['ROCKET']} ({Fore.YELLOW}{translator.get('menu.lifetime_access_enabled')}{Style.RESET_ALL})",
|
||||||
5: f"{Fore.GREEN}5{Style.RESET_ALL}. {EMOJI['SUCCESS']} {translator.get('menu.register_manual')}",
|
5: f"{Fore.GREEN}5{Style.RESET_ALL}. {EMOJI['SUCCESS']} {translator.get('menu.register_manual')}",
|
||||||
6: f"{Fore.GREEN}6{Style.RESET_ALL}. {EMOJI['RESET']} {translator.get('menu.temp_github_register')}",
|
6: f"{Fore.GREEN}6{Style.RESET_ALL}. {EMOJI['RESET']} {translator.get('menu.temp_github_register')}",
|
||||||
7: f"{Fore.GREEN}7{Style.RESET_ALL}. {EMOJI['ERROR']} {translator.get('menu.quit')}",
|
7: f"{Fore.GREEN}7{Style.RESET_ALL}. {EMOJI['ERROR']} {translator.get('menu.quit')}",
|
||||||
@@ -287,7 +287,8 @@ def print_menu():
|
|||||||
12: f"{Fore.GREEN}12{Style.RESET_ALL}. {EMOJI['SETTINGS']} {translator.get('menu.config')}",
|
12: f"{Fore.GREEN}12{Style.RESET_ALL}. {EMOJI['SETTINGS']} {translator.get('menu.config')}",
|
||||||
13: f"{Fore.GREEN}13{Style.RESET_ALL}. {EMOJI['SETTINGS']} {translator.get('menu.select_chrome_profile')}",
|
13: f"{Fore.GREEN}13{Style.RESET_ALL}. {EMOJI['SETTINGS']} {translator.get('menu.select_chrome_profile')}",
|
||||||
14: f"{Fore.GREEN}14{Style.RESET_ALL}. {EMOJI['ERROR']} {translator.get('menu.delete_google_account', fallback='Delete Cursor Google Account')}",
|
14: f"{Fore.GREEN}14{Style.RESET_ALL}. {EMOJI['ERROR']} {translator.get('menu.delete_google_account', fallback='Delete Cursor Google Account')}",
|
||||||
15: f"{Fore.GREEN}15{Style.RESET_ALL}. {EMOJI['UPDATE']} {translator.get('menu.bypass_version_check', fallback='Bypass Cursor Version Check')}"
|
15: f"{Fore.GREEN}15{Style.RESET_ALL}. {EMOJI['UPDATE']} {translator.get('menu.bypass_version_check', fallback='Bypass Cursor Version Check')}",
|
||||||
|
16: f"{Fore.GREEN}16{Style.RESET_ALL}. {EMOJI['UPDATE']} {translator.get('menu.check_user_authorized', fallback='Check User Authorized')}"
|
||||||
}
|
}
|
||||||
|
|
||||||
# Automatically calculate the number of menu items in the left and right columns
|
# Automatically calculate the number of menu items in the left and right columns
|
||||||
@@ -552,14 +553,15 @@ def main():
|
|||||||
if not config:
|
if not config:
|
||||||
print(f"{Fore.RED}{EMOJI['ERROR']} {translator.get('menu.config_init_failed')}{Style.RESET_ALL}")
|
print(f"{Fore.RED}{EMOJI['ERROR']} {translator.get('menu.config_init_failed')}{Style.RESET_ALL}")
|
||||||
return
|
return
|
||||||
|
force_update_config(translator)
|
||||||
|
|
||||||
if config.getboolean('Utils', 'enabled_update_check'):
|
if config.getboolean('Utils', 'enabled_update_check'):
|
||||||
check_latest_version() # Add version check before showing menu
|
check_latest_version() # Add version check before showing menu
|
||||||
print_menu()
|
print_menu()
|
||||||
|
|
||||||
while True:
|
while True:
|
||||||
try:
|
try:
|
||||||
choice_num = 15
|
choice_num = 16
|
||||||
choice = input(f"\n{EMOJI['ARROW']} {Fore.CYAN}{translator.get('menu.input_choice', choices=f'0-{choice_num}')}: {Style.RESET_ALL}")
|
choice = input(f"\n{EMOJI['ARROW']} {Fore.CYAN}{translator.get('menu.input_choice', choices=f'0-{choice_num}')}: {Style.RESET_ALL}")
|
||||||
|
|
||||||
if choice == "0":
|
if choice == "0":
|
||||||
@@ -629,6 +631,10 @@ def main():
|
|||||||
import bypass_version
|
import bypass_version
|
||||||
bypass_version.main(translator)
|
bypass_version.main(translator)
|
||||||
print_menu()
|
print_menu()
|
||||||
|
elif choice == "16":
|
||||||
|
import check_user_authorized
|
||||||
|
check_user_authorized.main(translator)
|
||||||
|
print_menu()
|
||||||
else:
|
else:
|
||||||
print(f"{Fore.RED}{EMOJI['ERROR']} {translator.get('menu.invalid_choice')}{Style.RESET_ALL}")
|
print(f"{Fore.RED}{EMOJI['ERROR']} {translator.get('menu.invalid_choice')}{Style.RESET_ALL}")
|
||||||
print_menu()
|
print_menu()
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ import configparser
|
|||||||
from new_signup import get_user_documents_path
|
from new_signup import get_user_documents_path
|
||||||
import traceback
|
import traceback
|
||||||
from config import get_config
|
from config import get_config
|
||||||
|
from datetime import datetime
|
||||||
|
|
||||||
# Initialize colorama
|
# Initialize colorama
|
||||||
init()
|
init()
|
||||||
@@ -220,8 +221,12 @@ def get_workbench_cursor_path(translator=None) -> str:
|
|||||||
|
|
||||||
if system == "Windows":
|
if system == "Windows":
|
||||||
base_path = config.get('WindowsPaths', 'cursor_path')
|
base_path = config.get('WindowsPaths', 'cursor_path')
|
||||||
else:
|
elif system == "Darwin":
|
||||||
base_path = paths_map[system]["base"]
|
base_path = paths_map[system]["base"]
|
||||||
|
else: # Linux
|
||||||
|
# For Linux, we've already checked all bases in the loop above
|
||||||
|
# If we're here, it means none of the bases worked, so we'll use the first one
|
||||||
|
base_path = paths_map[system]["bases"][0]
|
||||||
|
|
||||||
main_path = os.path.join(base_path, paths_map[system]["main"])
|
main_path = os.path.join(base_path, paths_map[system]["main"])
|
||||||
|
|
||||||
@@ -334,37 +339,40 @@ def modify_workbench_js(file_path: str, translator=None) -> bool:
|
|||||||
with open(file_path, "r", encoding="utf-8", errors="ignore") as main_file:
|
with open(file_path, "r", encoding="utf-8", errors="ignore") as main_file:
|
||||||
content = main_file.read()
|
content = main_file.read()
|
||||||
|
|
||||||
if sys.platform == "win32":
|
patterns = {
|
||||||
# Define replacement patterns
|
# 通用按钮替换模式
|
||||||
CButton_old_pattern = r'M(x,I(as,{title:"Upgrade to Pro",size:"small",get codicon(){return $.rocket},get onClick(){return t.pay}}),null)'
|
r'B(k,D(Ln,{title:"Upgrade to Pro",size:"small",get codicon(){return A.rocket},get onClick(){return t.pay}}),null)': r'B(k,D(Ln,{title:"yeongpin GitHub",size:"small",get codicon(){return A.github},get onClick(){return function(){window.open("https://github.com/yeongpin/cursor-free-vip","_blank")}}}),null)',
|
||||||
CButton_new_pattern = r'M(x,I(as,{title:"yeongpin GitHub",size:"small",get codicon(){return $.rocket},get onClick(){return function(){window.open("https://github.com/yeongpin/cursor-free-vip","_blank")}}}),null)'
|
|
||||||
elif sys.platform == "linux":
|
# Windows/Linux/Mac 通用按钮替换模式
|
||||||
CButton_old_pattern = r'M(x,I(as,{title:"Upgrade to Pro",size:"small",get codicon(){return $.rocket},get onClick(){return t.pay}}),null)'
|
r'M(x,I(as,{title:"Upgrade to Pro",size:"small",get codicon(){return $.rocket},get onClick(){return t.pay}}),null)': r'M(x,I(as,{title:"yeongpin GitHub",size:"small",get codicon(){return $.rocket},get onClick(){return function(){window.open("https://github.com/yeongpin/cursor-free-vip","_blank")}}}),null)',
|
||||||
CButton_new_pattern = r'M(x,I(as,{title:"yeongpin GitHub",size:"small",get codicon(){return $.rocket},get onClick(){return function(){window.open("https://github.com/yeongpin/cursor-free-vip","_blank")}}}),null)'
|
|
||||||
elif sys.platform == "darwin":
|
# Badge 替换
|
||||||
CButton_old_pattern = r'M(x,I(as,{title:"Upgrade to Pro",size:"small",get codicon(){return $.rocket},get onClick(){return t.pay}}),null)'
|
r'<div>Pro Trial': r'<div>Pro',
|
||||||
CButton_new_pattern = r'M(x,I(as,{title:"yeongpin GitHub",size:"small",get codicon(){return $.rocket},get onClick(){return function(){window.open("https://github.com/yeongpin/cursor-free-vip","_blank")}}}),null)'
|
|
||||||
|
|
||||||
CBadge_old_pattern = r'<div>Pro Trial'
|
r'py-1">Auto-select': r'py-1">Bypass-Version-Pin',
|
||||||
CBadge_new_pattern = r'<div>Pro'
|
|
||||||
|
#
|
||||||
|
r'async getEffectiveTokenLimit(e){const n=e.modelName;if(!n)return 2e5;':r'async getEffectiveTokenLimit(e){return 9000000;const n=e.modelName;if(!n)return 9e5;',
|
||||||
|
# Pro
|
||||||
|
r'var DWr=ne("<div class=settings__item_description>You are currently signed in with <strong></strong>.");': r'var DWr=ne("<div class=settings__item_description>You are currently signed in with <strong></strong>. <h1>Pro</h1>");',
|
||||||
|
|
||||||
|
# Toast 替换
|
||||||
|
r'notifications-toasts': r'notifications-toasts hidden'
|
||||||
|
}
|
||||||
|
|
||||||
CToast_old_pattern = r'notifications-toasts'
|
# 使用patterns进行替换
|
||||||
CToast_new_pattern = r'notifications-toasts hidden'
|
for old_pattern, new_pattern in patterns.items():
|
||||||
|
content = content.replace(old_pattern, new_pattern)
|
||||||
# Replace content
|
|
||||||
content = content.replace(CButton_old_pattern, CButton_new_pattern)
|
|
||||||
content = content.replace(CBadge_old_pattern, CBadge_new_pattern)
|
|
||||||
content = content.replace(CToast_old_pattern, CToast_new_pattern)
|
|
||||||
|
|
||||||
# Write to temporary file
|
# Write to temporary file
|
||||||
tmp_file.write(content)
|
tmp_file.write(content)
|
||||||
tmp_path = tmp_file.name
|
tmp_path = tmp_file.name
|
||||||
|
|
||||||
# Backup original file
|
# Backup original file with timestamp
|
||||||
backup_path = file_path + ".backup"
|
timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
|
||||||
if os.path.exists(backup_path):
|
backup_path = f"{file_path}.backup.{timestamp}"
|
||||||
os.remove(backup_path)
|
|
||||||
shutil.copy2(file_path, backup_path)
|
shutil.copy2(file_path, backup_path)
|
||||||
|
print(f"{Fore.GREEN}{EMOJI['SUCCESS']} {translator.get('reset.backup_created', path=backup_path)}{Style.RESET_ALL}")
|
||||||
|
|
||||||
# Move temporary file to original position
|
# Move temporary file to original position
|
||||||
if os.path.exists(file_path):
|
if os.path.exists(file_path):
|
||||||
@@ -411,7 +419,10 @@ def modify_main_js(main_path: str, translator) -> bool:
|
|||||||
tmp_file.write(content)
|
tmp_file.write(content)
|
||||||
tmp_path = tmp_file.name
|
tmp_path = tmp_file.name
|
||||||
|
|
||||||
shutil.copy2(main_path, main_path + ".old")
|
timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
|
||||||
|
backup_path = f"{main_path}.old.{timestamp}"
|
||||||
|
shutil.copy2(main_path, backup_path)
|
||||||
|
print(f"{Fore.GREEN}{EMOJI['SUCCESS']} {translator.get('reset.backup_created', path=backup_path)}{Style.RESET_ALL}")
|
||||||
shutil.move(tmp_path, main_path)
|
shutil.move(tmp_path, main_path)
|
||||||
|
|
||||||
os.chmod(main_path, original_mode)
|
os.chmod(main_path, original_mode)
|
||||||
@@ -461,7 +472,8 @@ def patch_cursor_get_machine_id(translator) -> bool:
|
|||||||
print(f"{Fore.CYAN}{EMOJI['INFO']} {translator.get('reset.version_check_passed')}{Style.RESET_ALL}")
|
print(f"{Fore.CYAN}{EMOJI['INFO']} {translator.get('reset.version_check_passed')}{Style.RESET_ALL}")
|
||||||
|
|
||||||
# Backup file
|
# Backup file
|
||||||
backup_path = main_path + ".bak"
|
timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
|
||||||
|
backup_path = f"{main_path}.bak.{timestamp}"
|
||||||
if not os.path.exists(backup_path):
|
if not os.path.exists(backup_path):
|
||||||
shutil.copy2(main_path, 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}")
|
print(f"{Fore.GREEN}{EMOJI['SUCCESS']} {translator.get('reset.backup_created', path=backup_path)}{Style.RESET_ALL}")
|
||||||
@@ -638,8 +650,8 @@ class MachineIDResetter:
|
|||||||
winreg.SetValueEx(key, "MachineGuid", 0, winreg.REG_SZ, new_guid)
|
winreg.SetValueEx(key, "MachineGuid", 0, winreg.REG_SZ, new_guid)
|
||||||
winreg.CloseKey(key)
|
winreg.CloseKey(key)
|
||||||
print(f"{Fore.GREEN}{EMOJI['SUCCESS']} {self.translator.get('reset.windows_machine_guid_updated')}{Style.RESET_ALL}")
|
print(f"{Fore.GREEN}{EMOJI['SUCCESS']} {self.translator.get('reset.windows_machine_guid_updated')}{Style.RESET_ALL}")
|
||||||
except PermissionError:
|
except PermissionError as e:
|
||||||
print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('reset.permission_denied')}{Style.RESET_ALL}")
|
print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('reset.permission_denied', error=str(e))}{Style.RESET_ALL}")
|
||||||
raise
|
raise
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('reset.update_windows_machine_guid_failed', error=str(e))}{Style.RESET_ALL}")
|
print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('reset.update_windows_machine_guid_failed', error=str(e))}{Style.RESET_ALL}")
|
||||||
@@ -717,12 +729,10 @@ class MachineIDResetter:
|
|||||||
with open(self.db_path, "r", encoding="utf-8") as f:
|
with open(self.db_path, "r", encoding="utf-8") as f:
|
||||||
config = json.load(f)
|
config = json.load(f)
|
||||||
|
|
||||||
backup_path = self.db_path + ".bak"
|
timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
|
||||||
if not os.path.exists(backup_path):
|
backup_path = f"{self.db_path}.bak.{timestamp}"
|
||||||
print(f"{Fore.YELLOW}{EMOJI['BACKUP']} {self.translator.get('reset.creating_backup')}: {backup_path}{Style.RESET_ALL}")
|
print(f"{Fore.YELLOW}{EMOJI['BACKUP']} {self.translator.get('reset.creating_backup')}: {backup_path}{Style.RESET_ALL}")
|
||||||
shutil.copy2(self.db_path, backup_path)
|
shutil.copy2(self.db_path, backup_path)
|
||||||
else:
|
|
||||||
print(f"{Fore.YELLOW}{EMOJI['INFO']} {self.translator.get('reset.backup_exists')}{Style.RESET_ALL}")
|
|
||||||
|
|
||||||
print(f"{Fore.CYAN}{EMOJI['RESET']} {self.translator.get('reset.generating')}...{Style.RESET_ALL}")
|
print(f"{Fore.CYAN}{EMOJI['RESET']} {self.translator.get('reset.generating')}...{Style.RESET_ALL}")
|
||||||
new_ids = self.generate_new_ids()
|
new_ids = self.generate_new_ids()
|
||||||
@@ -786,7 +796,8 @@ class MachineIDResetter:
|
|||||||
|
|
||||||
# Create backup if file exists
|
# Create backup if file exists
|
||||||
if os.path.exists(machine_id_path):
|
if os.path.exists(machine_id_path):
|
||||||
backup_path = machine_id_path + ".backup"
|
timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
|
||||||
|
backup_path = f"{machine_id_path}.backup.{timestamp}"
|
||||||
try:
|
try:
|
||||||
shutil.copy2(machine_id_path, backup_path)
|
shutil.copy2(machine_id_path, backup_path)
|
||||||
print(f"{Fore.GREEN}{EMOJI['INFO']} {self.translator.get('reset.backup_created', path=backup_path) if self.translator else f'Backup created at: {backup_path}'}{Style.RESET_ALL}")
|
print(f"{Fore.GREEN}{EMOJI['INFO']} {self.translator.get('reset.backup_created', path=backup_path) if self.translator else f'Backup created at: {backup_path}'}{Style.RESET_ALL}")
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ EMOJI = {
|
|||||||
"SUCCESS": "✅",
|
"SUCCESS": "✅",
|
||||||
"ERROR": "❌",
|
"ERROR": "❌",
|
||||||
"INFO": "ℹ️",
|
"INFO": "ℹ️",
|
||||||
"RESET": "<EFBFBD><EFBFBD>",
|
"RESET": "🔄",
|
||||||
"WARNING": "⚠️",
|
"WARNING": "⚠️",
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -111,7 +111,7 @@ def get_cursor_paths(translator=None) -> Tuple[str, str]:
|
|||||||
# For Linux, try to find the first existing path if the configured one doesn't exist
|
# For Linux, try to find the first existing path if the configured one doesn't exist
|
||||||
if system == "Linux" and not os.path.exists(base_path):
|
if system == "Linux" and not os.path.exists(base_path):
|
||||||
for path in default_paths["Linux"]:
|
for path in default_paths["Linux"]:
|
||||||
if os.path.exists(path):
|
if os.path.exists(path):
|
||||||
base_path = path
|
base_path = path
|
||||||
# Update config with the found path
|
# Update config with the found path
|
||||||
config.set(section, 'cursor_path', path)
|
config.set(section, 'cursor_path', path)
|
||||||
@@ -529,7 +529,7 @@ class MachineIDResetter:
|
|||||||
self.db_path = config.get('LinuxPaths', 'storage_path')
|
self.db_path = config.get('LinuxPaths', 'storage_path')
|
||||||
self.sqlite_path = config.get('LinuxPaths', 'sqlite_path')
|
self.sqlite_path = config.get('LinuxPaths', 'sqlite_path')
|
||||||
|
|
||||||
else:
|
else:
|
||||||
raise NotImplementedError(f"Not Supported OS: {sys.platform}")
|
raise NotImplementedError(f"Not Supported OS: {sys.platform}")
|
||||||
|
|
||||||
# Save any changes to config file
|
# Save any changes to config file
|
||||||
@@ -811,4 +811,4 @@ def run(translator=None):
|
|||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
from main import translator as main_translator
|
from main import translator as main_translator
|
||||||
run(main_translator)
|
run(main_translator)
|
||||||
Reference in New Issue
Block a user