mirror of
https://github.com/yeongpin/cursor-free-vip.git
synced 2025-04-24 08:25:23 +00:00
Update version to 1.9.06 and remove deprecated cursor authentication and registration scripts
This commit is contained in:
parent
33a497bf52
commit
da9d4a3648
@ -1,5 +0,0 @@
|
||||
// Import the contents of your other files
|
||||
importScripts('default_filters.js', 'block.js');
|
||||
|
||||
// Your service worker initialization code can go here
|
||||
console.log('Service worker initialized');
|
129
PBlock/block.js
129
PBlock/block.js
@ -1,129 +0,0 @@
|
||||
/**
|
||||
* All the actual functionality of the extension; loads as part of the background page.
|
||||
*
|
||||
* Active ingredient is enable(), which sets up the webRequest callbacks.
|
||||
*
|
||||
* */
|
||||
|
||||
let blockingEnabled = false;
|
||||
let allFilters = null;
|
||||
let webRTCPrivacy = null;
|
||||
|
||||
function setFilters(newFilters) {
|
||||
allFilters = newFilters;
|
||||
chrome.storage.local.set({"filters": newFilters});
|
||||
if (blockingEnabled) {
|
||||
refreshFilters();
|
||||
}
|
||||
}
|
||||
|
||||
// Convert URL patterns to declarativeNetRequest rule format
|
||||
function createRules(filters) {
|
||||
return filters.map((filter, index) => ({
|
||||
id: index + 1,
|
||||
priority: 1,
|
||||
action: {
|
||||
type: "block"
|
||||
},
|
||||
condition: {
|
||||
urlFilter: filter.replace("*://", "*"),
|
||||
resourceTypes: [
|
||||
"main_frame", "sub_frame", "stylesheet", "script", "image",
|
||||
"font", "object", "xmlhttprequest", "ping", "media", "websocket"
|
||||
]
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
async function enable(icon = true) {
|
||||
if (blockingEnabled) return;
|
||||
|
||||
if (allFilters && allFilters.length > 0) {
|
||||
const rules = createRules(allFilters);
|
||||
await chrome.declarativeNetRequest.updateDynamicRules({
|
||||
removeRuleIds: rules.map(rule => rule.id),
|
||||
addRules: rules
|
||||
});
|
||||
}
|
||||
|
||||
blockingEnabled = true;
|
||||
if (icon) {
|
||||
chrome.action.setIcon({
|
||||
path: {
|
||||
"16": "enabled16.png",
|
||||
"48": "enabled48.png"
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
async function disable(icon = true) {
|
||||
if (!blockingEnabled) return;
|
||||
|
||||
const rules = await chrome.declarativeNetRequest.getDynamicRules();
|
||||
await chrome.declarativeNetRequest.updateDynamicRules({
|
||||
removeRuleIds: rules.map(rule => rule.id),
|
||||
addRules: []
|
||||
});
|
||||
|
||||
blockingEnabled = false;
|
||||
if (icon) {
|
||||
chrome.action.setIcon({
|
||||
path: {
|
||||
"16": "disabled.png",
|
||||
"32": "disabled.png"
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
async function refreshFilters() {
|
||||
await disable(false);
|
||||
await enable(true);
|
||||
}
|
||||
|
||||
async function toggleEnabled() {
|
||||
if (blockingEnabled) {
|
||||
await disable();
|
||||
} else {
|
||||
await enable();
|
||||
}
|
||||
}
|
||||
|
||||
function setWebRTCPrivacy(flag, store = true) {
|
||||
webRTCPrivacy = flag;
|
||||
const privacySetting = flag ? "default_public_interface_only" : "default";
|
||||
chrome.privacy.network.webRTCIPHandlingPolicy.set({value: privacySetting});
|
||||
if (store) {
|
||||
chrome.storage.local.set({"webrtc_privacy": flag});
|
||||
}
|
||||
}
|
||||
|
||||
// Initialization
|
||||
chrome.storage.local.get("filters",
|
||||
function(result) {
|
||||
if (result["filters"] == undefined) {
|
||||
console.log("Initializing filters to defaults.");
|
||||
setFilters(defaultFilters);
|
||||
} else {
|
||||
setFilters(result["filters"]);
|
||||
allFilters = result["filters"];
|
||||
}
|
||||
|
||||
// toggle blocking on-off via the extension icon
|
||||
chrome.action.onClicked.addListener(toggleEnabled);
|
||||
// initialize blocking
|
||||
enable();
|
||||
}
|
||||
);
|
||||
|
||||
chrome.storage.local.get("webrtc_privacy",
|
||||
function(result) {
|
||||
if (result["webrtc_privacy"] == undefined) {
|
||||
console.log("Initializing WebRTC privacy to default.");
|
||||
setWebRTCPrivacy(false, true);
|
||||
} else {
|
||||
setWebRTCPrivacy(result["webrtc_privacy"], false);
|
||||
}
|
||||
}
|
||||
);
|
@ -1,14 +0,0 @@
|
||||
defaultFilters = [
|
||||
// personally, I can't stand the like box
|
||||
//"http://www.facebook.com/plugins/likebox.php?*",
|
||||
"*://*.doubleclick.net/*",
|
||||
"*://partner.googleadservices.com/*",
|
||||
"*://*.googlesyndication.com/*",
|
||||
"*://*.google-analytics.com/*",
|
||||
"*://creative.ak.fbcdn.net/*",
|
||||
"*://*.adbrite.com/*",
|
||||
"*://*.exponential.com/*",
|
||||
"*://*.quantserve.com/*",
|
||||
"*://*.scorecardresearch.com/*",
|
||||
"*://*.zedo.com/*",
|
||||
]
|
Binary file not shown.
Before Width: | Height: | Size: 850 B |
Binary file not shown.
Before Width: | Height: | Size: 3.4 KiB |
@ -1,29 +0,0 @@
|
||||
{
|
||||
"name": "PBlock",
|
||||
"version": "0.1",
|
||||
"manifest_version": 3,
|
||||
"author": "yeongpin",
|
||||
"url": "https://github.com/yeongpin/PBlock",
|
||||
"description": "Just a simple blocker.",
|
||||
"action": {
|
||||
"default_icon": "enabled48.png"
|
||||
},
|
||||
"background": {
|
||||
"service_worker": "background.js"
|
||||
},
|
||||
"icons": {
|
||||
"16": "enabled16.png",
|
||||
"48": "enabled48.png"
|
||||
},
|
||||
"permissions": [
|
||||
"declarativeNetRequest",
|
||||
"storage",
|
||||
"privacy"
|
||||
],
|
||||
"host_permissions": [
|
||||
"http://*/*",
|
||||
"https://*/*",
|
||||
"ws://*/*",
|
||||
"wss://*/*"
|
||||
]
|
||||
}
|
@ -1,5 +0,0 @@
|
||||
{
|
||||
"id": "ruleset_1",
|
||||
"version": "1.0",
|
||||
"rules": []
|
||||
}
|
15
build.spec
15
build.spec
@ -23,29 +23,14 @@ a = Analysis(
|
||||
pathex=[],
|
||||
binaries=[],
|
||||
datas=[
|
||||
('turnstilePatch', 'turnstilePatch'),
|
||||
('PBlock', 'PBlock'),
|
||||
('locales', 'locales'),
|
||||
('cursor_auth.py', '.'),
|
||||
('reset_machine_manual.py', '.'),
|
||||
('cursor_register.py', '.'),
|
||||
('new_signup.py', '.'),
|
||||
('new_tempemail.py', '.'),
|
||||
('quit_cursor.py', '.'),
|
||||
('cursor_register_manual.py', '.'),
|
||||
('oauth_auth.py', '.'),
|
||||
('utils.py', '.'),
|
||||
('.env', '.'),
|
||||
('block_domain.txt', '.')
|
||||
],
|
||||
hiddenimports=[
|
||||
'cursor_auth',
|
||||
'reset_machine_manual',
|
||||
'new_signup',
|
||||
'new_tempemail',
|
||||
'quit_cursor',
|
||||
'cursor_register_manual',
|
||||
'oauth_auth',
|
||||
'utils'
|
||||
],
|
||||
hookspath=[],
|
||||
|
159
cursor_auth.py
159
cursor_auth.py
@ -1,159 +0,0 @@
|
||||
import sqlite3
|
||||
import os
|
||||
import sys
|
||||
from colorama import Fore, Style, init
|
||||
from config import get_config
|
||||
|
||||
# Initialize colorama
|
||||
init()
|
||||
|
||||
# Define emoji and color constants
|
||||
EMOJI = {
|
||||
'DB': '🗄️',
|
||||
'UPDATE': '🔄',
|
||||
'SUCCESS': '✅',
|
||||
'ERROR': '❌',
|
||||
'WARN': '⚠️',
|
||||
'INFO': 'ℹ️',
|
||||
'FILE': '📄',
|
||||
'KEY': '🔐'
|
||||
}
|
||||
|
||||
class CursorAuth:
|
||||
def __init__(self, translator=None):
|
||||
self.translator = translator
|
||||
|
||||
# Get configuration
|
||||
config = get_config(translator)
|
||||
if not config:
|
||||
print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('auth.config_error') if self.translator else 'Failed to load configuration'}{Style.RESET_ALL}")
|
||||
sys.exit(1)
|
||||
|
||||
# Get path based on operating system
|
||||
try:
|
||||
if sys.platform == "win32": # Windows
|
||||
if not config.has_section('WindowsPaths'):
|
||||
raise ValueError("Windows paths not configured")
|
||||
self.db_path = config.get('WindowsPaths', 'sqlite_path')
|
||||
|
||||
elif sys.platform == 'linux': # Linux
|
||||
if not config.has_section('LinuxPaths'):
|
||||
raise ValueError("Linux paths not configured")
|
||||
self.db_path = config.get('LinuxPaths', 'sqlite_path')
|
||||
|
||||
elif sys.platform == 'darwin': # macOS
|
||||
if not config.has_section('MacPaths'):
|
||||
raise ValueError("macOS paths not configured")
|
||||
self.db_path = config.get('MacPaths', 'sqlite_path')
|
||||
|
||||
else:
|
||||
print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('auth.unsupported_platform') if self.translator else 'Unsupported platform'}{Style.RESET_ALL}")
|
||||
sys.exit(1)
|
||||
|
||||
# Verify if the path exists
|
||||
if not os.path.exists(os.path.dirname(self.db_path)):
|
||||
raise FileNotFoundError(f"Database directory not found: {os.path.dirname(self.db_path)}")
|
||||
|
||||
except Exception as e:
|
||||
print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('auth.path_error', error=str(e)) if self.translator else f'Error getting database path: {str(e)}'}{Style.RESET_ALL}")
|
||||
sys.exit(1)
|
||||
|
||||
# Check if the database file exists
|
||||
if not os.path.exists(self.db_path):
|
||||
print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('auth.db_not_found', path=self.db_path)}{Style.RESET_ALL}")
|
||||
return
|
||||
|
||||
# Check file permissions
|
||||
if not os.access(self.db_path, os.R_OK | os.W_OK):
|
||||
print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('auth.db_permission_error')}{Style.RESET_ALL}")
|
||||
return
|
||||
|
||||
try:
|
||||
self.conn = sqlite3.connect(self.db_path)
|
||||
print(f"{Fore.GREEN}{EMOJI['SUCCESS']} {self.translator.get('auth.connected_to_database')}{Style.RESET_ALL}")
|
||||
except sqlite3.Error as e:
|
||||
print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('auth.db_connection_error', error=str(e))}{Style.RESET_ALL}")
|
||||
return
|
||||
|
||||
def update_auth(self, email=None, access_token=None, refresh_token=None):
|
||||
conn = None
|
||||
try:
|
||||
# Ensure the directory exists and set the correct permissions
|
||||
db_dir = os.path.dirname(self.db_path)
|
||||
if not os.path.exists(db_dir):
|
||||
os.makedirs(db_dir, mode=0o755, exist_ok=True)
|
||||
|
||||
# If the database file does not exist, create a new one
|
||||
if not os.path.exists(self.db_path):
|
||||
conn = sqlite3.connect(self.db_path)
|
||||
cursor = conn.cursor()
|
||||
cursor.execute('''
|
||||
CREATE TABLE IF NOT EXISTS ItemTable (
|
||||
key TEXT PRIMARY KEY,
|
||||
value TEXT
|
||||
)
|
||||
''')
|
||||
conn.commit()
|
||||
if sys.platform != "win32":
|
||||
os.chmod(self.db_path, 0o644)
|
||||
conn.close()
|
||||
|
||||
# Reconnect to the database
|
||||
conn = sqlite3.connect(self.db_path)
|
||||
print(f"{EMOJI['INFO']} {Fore.GREEN} {self.translator.get('auth.connected_to_database')}{Style.RESET_ALL}")
|
||||
cursor = conn.cursor()
|
||||
|
||||
# Add timeout and other optimization settings
|
||||
conn.execute("PRAGMA busy_timeout = 5000")
|
||||
conn.execute("PRAGMA journal_mode = WAL")
|
||||
conn.execute("PRAGMA synchronous = NORMAL")
|
||||
|
||||
# Set the key-value pairs to update
|
||||
updates = []
|
||||
|
||||
updates.append(("cursorAuth/cachedSignUpType", "Auth_0"))
|
||||
|
||||
if email is not None:
|
||||
updates.append(("cursorAuth/cachedEmail", email))
|
||||
if access_token is not None:
|
||||
updates.append(("cursorAuth/accessToken", access_token))
|
||||
if refresh_token is not None:
|
||||
updates.append(("cursorAuth/refreshToken", refresh_token))
|
||||
|
||||
|
||||
# Use transactions to ensure data integrity
|
||||
cursor.execute("BEGIN TRANSACTION")
|
||||
try:
|
||||
for key, value in updates:
|
||||
# Check if the key exists
|
||||
cursor.execute("SELECT COUNT(*) FROM ItemTable WHERE key = ?", (key,))
|
||||
if cursor.fetchone()[0] == 0:
|
||||
cursor.execute("""
|
||||
INSERT INTO ItemTable (key, value)
|
||||
VALUES (?, ?)
|
||||
""", (key, value))
|
||||
else:
|
||||
cursor.execute("""
|
||||
UPDATE ItemTable SET value = ?
|
||||
WHERE key = ?
|
||||
""", (value, key))
|
||||
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}")
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
cursor.execute("ROLLBACK")
|
||||
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}")
|
||||
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}")
|
||||
return False
|
||||
finally:
|
||||
if conn:
|
||||
conn.close()
|
||||
print(f"{EMOJI['DB']} {Fore.CYAN} {self.translator.get('auth.database_connection_closed')}{Style.RESET_ALL}")
|
@ -1,264 +0,0 @@
|
||||
import os
|
||||
from colorama import Fore, Style, init
|
||||
import time
|
||||
import random
|
||||
from cursor_auth import CursorAuth
|
||||
from reset_machine_manual import MachineIDResetter
|
||||
from get_user_token import get_token_from_cookie
|
||||
|
||||
os.environ["PYTHONVERBOSE"] = "0"
|
||||
os.environ["PYINSTALLER_VERBOSE"] = "0"
|
||||
|
||||
# Initialize colorama
|
||||
init()
|
||||
|
||||
# Define emoji constants
|
||||
EMOJI = {
|
||||
'START': '🚀',
|
||||
'FORM': '📝',
|
||||
'VERIFY': '🔄',
|
||||
'PASSWORD': '🔑',
|
||||
'CODE': '📱',
|
||||
'DONE': '✨',
|
||||
'ERROR': '❌',
|
||||
'WAIT': '⏳',
|
||||
'SUCCESS': '✅',
|
||||
'MAIL': '📧',
|
||||
'KEY': '🔐',
|
||||
'UPDATE': '🔄',
|
||||
'INFO': 'ℹ️'
|
||||
}
|
||||
|
||||
class CursorRegistration:
|
||||
def __init__(self, translator=None):
|
||||
self.translator = translator
|
||||
# Set to display mode
|
||||
os.environ['BROWSER_HEADLESS'] = 'False'
|
||||
self.browser = None
|
||||
self.controller = None
|
||||
self.mail_url = "https://yopmail.com/zh/email-generator"
|
||||
self.sign_up_url = "https://authenticator.cursor.sh/sign-up"
|
||||
self.settings_url = "https://www.cursor.com/settings"
|
||||
self.email_address = None
|
||||
self.signup_tab = None
|
||||
self.email_tab = None
|
||||
|
||||
# Account information
|
||||
self.password = self._generate_password()
|
||||
# Generate first name and last name separately
|
||||
first_name = random.choice([
|
||||
"James", "John", "Robert", "Michael", "William", "David", "Joseph", "Thomas",
|
||||
"Emma", "Olivia", "Ava", "Isabella", "Sophia", "Mia", "Charlotte", "Amelia",
|
||||
"Liam", "Noah", "Oliver", "Elijah", "Lucas", "Mason", "Logan", "Alexander"
|
||||
])
|
||||
self.last_name = random.choice([
|
||||
"Smith", "Johnson", "Williams", "Brown", "Jones", "Garcia", "Miller", "Davis",
|
||||
"Anderson", "Wilson", "Taylor", "Thomas", "Moore", "Martin", "Jackson", "Lee",
|
||||
"Thompson", "White", "Harris", "Clark", "Lewis", "Walker", "Hall", "Young"
|
||||
])
|
||||
|
||||
# Modify first letter of first name
|
||||
new_first_letter = random.choice("ABCDEFGHIJKLMNOPQRSTUVWXYZ")
|
||||
self.first_name = new_first_letter + first_name[1:]
|
||||
|
||||
print(f"\n{Fore.CYAN}{EMOJI['PASSWORD']} {self.translator.get('register.password')}: {self.password} {Style.RESET_ALL}")
|
||||
print(f"{Fore.CYAN}{EMOJI['FORM']} {self.translator.get('register.first_name')}: {self.first_name} {Style.RESET_ALL}")
|
||||
print(f"{Fore.CYAN}{EMOJI['FORM']} {self.translator.get('register.last_name')}: {self.last_name} {Style.RESET_ALL}")
|
||||
|
||||
def _generate_password(self, length=12):
|
||||
"""Generate Random Password"""
|
||||
chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!@#$%^&*"
|
||||
return ''.join(random.choices(chars, k=length))
|
||||
|
||||
def setup_email(self):
|
||||
"""Setup Email"""
|
||||
try:
|
||||
print(f"{Fore.CYAN}{EMOJI['START']} {self.translator.get('register.browser_start')}...{Style.RESET_ALL}")
|
||||
|
||||
# Create a temporary email using new_tempemail, passing translator
|
||||
from new_tempemail import NewTempEmail
|
||||
self.temp_email = NewTempEmail(self.translator) # Pass translator
|
||||
|
||||
# Create a temporary 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
|
||||
|
||||
# Save email address
|
||||
self.email_address = email_address
|
||||
self.email_tab = self.temp_email # Pass NewTempEmail instance
|
||||
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
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"""
|
||||
browser_tab = None
|
||||
try:
|
||||
print(f"{Fore.CYAN}{EMOJI['START']} {self.translator.get('register.register_start')}...{Style.RESET_ALL}")
|
||||
|
||||
# Directly use new_signup.py to sign up
|
||||
from new_signup import main as new_signup_main
|
||||
|
||||
# Execute the new registration process, passing 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
|
||||
)
|
||||
|
||||
if result:
|
||||
# Use the returned browser instance to get account information
|
||||
self.signup_tab = browser_tab # Save browser instance
|
||||
success = self._get_account_info()
|
||||
|
||||
# Close browser after getting information
|
||||
if browser_tab:
|
||||
try:
|
||||
browser_tab.quit()
|
||||
except:
|
||||
pass
|
||||
|
||||
return success
|
||||
|
||||
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:
|
||||
# Ensure browser is closed in any case
|
||||
if browser_tab:
|
||||
try:
|
||||
browser_tab.quit()
|
||||
except:
|
||||
pass
|
||||
|
||||
def _get_account_info(self):
|
||||
"""Get Account Information and Token"""
|
||||
try:
|
||||
self.signup_tab.get(self.settings_url)
|
||||
time.sleep(2)
|
||||
|
||||
usage_selector = (
|
||||
"css:div.col-span-2 > div > div > div > div > "
|
||||
"div:nth-child(1) > div.flex.items-center.justify-between.gap-2 > "
|
||||
"span.font-mono.text-sm\\/\\[0\\.875rem\\]"
|
||||
)
|
||||
usage_ele = self.signup_tab.ele(usage_selector)
|
||||
total_usage = "未知"
|
||||
if usage_ele:
|
||||
total_usage = usage_ele.text.split("/")[-1].strip()
|
||||
|
||||
print(f"{Fore.CYAN}{EMOJI['INFO']} {self.translator.get('register.total_usage', usage=total_usage)}{Style.RESET_ALL}")
|
||||
print(f"{Fore.CYAN}{EMOJI['WAIT']} {self.translator.get('register.get_token')}...{Style.RESET_ALL}")
|
||||
max_attempts = 30
|
||||
retry_interval = 2
|
||||
attempts = 0
|
||||
|
||||
while attempts < max_attempts:
|
||||
try:
|
||||
cookies = self.signup_tab.cookies()
|
||||
for cookie in cookies:
|
||||
if cookie.get("name") == "WorkosCursorSessionToken":
|
||||
token = get_token_from_cookie(cookie["value"], self.translator)
|
||||
print(f"{Fore.GREEN}{EMOJI['SUCCESS']} {self.translator.get('register.token_success')}{Style.RESET_ALL}")
|
||||
self._save_account_info(token, total_usage)
|
||||
return True
|
||||
|
||||
attempts += 1
|
||||
if attempts < max_attempts:
|
||||
print(f"{Fore.YELLOW}{EMOJI['WAIT']} {self.translator.get('register.token_attempt', attempt=attempts, time=retry_interval)}{Style.RESET_ALL}")
|
||||
time.sleep(retry_interval)
|
||||
else:
|
||||
print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('register.token_max_attempts', max=max_attempts)}{Style.RESET_ALL}")
|
||||
|
||||
except Exception as e:
|
||||
print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('register.token_failed', error=str(e))}{Style.RESET_ALL}")
|
||||
attempts += 1
|
||||
if attempts < max_attempts:
|
||||
print(f"{Fore.YELLOW}{EMOJI['WAIT']} {self.translator.get('register.token_attempt', attempt=attempts, time=retry_interval)}{Style.RESET_ALL}")
|
||||
time.sleep(retry_interval)
|
||||
|
||||
return False
|
||||
|
||||
except Exception as e:
|
||||
print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('register.account_error', error=str(e))}{Style.RESET_ALL}")
|
||||
return False
|
||||
|
||||
def _save_account_info(self, token, total_usage):
|
||||
"""Save Account Information to File"""
|
||||
try:
|
||||
# Update authentication information first
|
||||
print(f"{Fore.CYAN}{EMOJI['KEY']} {self.translator.get('register.update_cursor_auth_info')}...{Style.RESET_ALL}")
|
||||
if self.update_cursor_auth(email=self.email_address, access_token=token, refresh_token=token):
|
||||
print(f"{Fore.GREEN}{EMOJI['SUCCESS']} {self.translator.get('register.cursor_auth_info_updated')}...{Style.RESET_ALL}")
|
||||
else:
|
||||
print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('register.cursor_auth_info_update_failed')}...{Style.RESET_ALL}")
|
||||
|
||||
# Reset machine ID
|
||||
print(f"{Fore.CYAN}{EMOJI['UPDATE']} {self.translator.get('register.reset_machine_id')}...{Style.RESET_ALL}")
|
||||
resetter = MachineIDResetter(self.translator) # Pass translator when creating instance
|
||||
if not resetter.reset_machine_ids(): # Call reset_machine_ids method directly
|
||||
raise Exception("Failed to reset machine ID")
|
||||
|
||||
# Save account information to file
|
||||
with open('cursor_accounts.txt', 'a', encoding='utf-8') as f:
|
||||
f.write(f"\n{'='*50}\n")
|
||||
f.write(f"Email: {self.email_address}\n")
|
||||
f.write(f"Password: {self.password}\n")
|
||||
f.write(f"Token: {token}\n")
|
||||
f.write(f"Usage Limit: {total_usage}\n")
|
||||
f.write(f"{'='*50}\n")
|
||||
|
||||
print(f"{Fore.GREEN}{EMOJI['SUCCESS']} {self.translator.get('register.account_info_saved')}...{Style.RESET_ALL}")
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('register.save_account_info_failed', error=str(e))}{Style.RESET_ALL}")
|
||||
return False
|
||||
|
||||
def start(self):
|
||||
"""Start Registration Process"""
|
||||
try:
|
||||
if self.setup_email():
|
||||
if self.register_cursor():
|
||||
print(f"\n{Fore.GREEN}{EMOJI['DONE']} {self.translator.get('register.cursor_registration_completed')}...{Style.RESET_ALL}")
|
||||
return True
|
||||
return False
|
||||
finally:
|
||||
# Close email tab
|
||||
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):
|
||||
"""Update Cursor Auth Info"""
|
||||
auth_manager = CursorAuth(translator=self.translator)
|
||||
return auth_manager.update_auth(email, access_token, refresh_token)
|
||||
|
||||
def main(translator=None):
|
||||
"""Main function to be called from main.py"""
|
||||
print(f"\n{Fore.CYAN}{'='*50}{Style.RESET_ALL}")
|
||||
print(f"{Fore.CYAN}{EMOJI['START']} {translator.get('register.title')}{Style.RESET_ALL}")
|
||||
print(f"{Fore.CYAN}{'='*50}{Style.RESET_ALL}")
|
||||
|
||||
registration = CursorRegistration(translator)
|
||||
registration.start()
|
||||
|
||||
print(f"\n{Fore.CYAN}{'='*50}{Style.RESET_ALL}")
|
||||
input(f"{EMOJI['INFO']} {translator.get('register.press_enter')}...")
|
||||
|
||||
if __name__ == "__main__":
|
||||
from main import translator as main_translator
|
||||
main(main_translator)
|
@ -1,5 +0,0 @@
|
||||
from oauth_auth import main as oauth_main
|
||||
|
||||
def main(translator=None):
|
||||
"""Handle GitHub OAuth registration"""
|
||||
oauth_main('github', translator)
|
@ -1,5 +0,0 @@
|
||||
from oauth_auth import main as oauth_main
|
||||
|
||||
def main(translator=None):
|
||||
"""Handle Google OAuth registration"""
|
||||
oauth_main('google', translator)
|
@ -1,271 +0,0 @@
|
||||
import os
|
||||
from colorama import Fore, Style, init
|
||||
import time
|
||||
import random
|
||||
from cursor_auth import CursorAuth
|
||||
from reset_machine_manual import MachineIDResetter
|
||||
from get_user_token import get_token_from_cookie
|
||||
|
||||
os.environ["PYTHONVERBOSE"] = "0"
|
||||
os.environ["PYINSTALLER_VERBOSE"] = "0"
|
||||
|
||||
# Initialize colorama
|
||||
init()
|
||||
|
||||
# Define emoji constants
|
||||
EMOJI = {
|
||||
'START': '🚀',
|
||||
'FORM': '📝',
|
||||
'VERIFY': '🔄',
|
||||
'PASSWORD': '🔑',
|
||||
'CODE': '📱',
|
||||
'DONE': '✨',
|
||||
'ERROR': '❌',
|
||||
'WAIT': '⏳',
|
||||
'SUCCESS': '✅',
|
||||
'MAIL': '📧',
|
||||
'KEY': '🔐',
|
||||
'UPDATE': '🔄',
|
||||
'INFO': 'ℹ️'
|
||||
}
|
||||
|
||||
class CursorRegistration:
|
||||
def __init__(self, translator=None):
|
||||
self.translator = translator
|
||||
# Set to display mode
|
||||
os.environ['BROWSER_HEADLESS'] = 'False'
|
||||
self.browser = None
|
||||
self.controller = None
|
||||
self.sign_up_url = "https://authenticator.cursor.sh/sign-up"
|
||||
self.settings_url = "https://www.cursor.com/settings"
|
||||
self.email_address = None
|
||||
self.signup_tab = None
|
||||
self.email_tab = None
|
||||
|
||||
# Generate account information
|
||||
self.password = self._generate_password()
|
||||
# Generate first name and last name separately
|
||||
first_name = random.choice([
|
||||
"James", "John", "Robert", "Michael", "William", "David", "Joseph", "Thomas",
|
||||
"Emma", "Olivia", "Ava", "Isabella", "Sophia", "Mia", "Charlotte", "Amelia",
|
||||
"Liam", "Noah", "Oliver", "Elijah", "Lucas", "Mason", "Logan", "Alexander"
|
||||
])
|
||||
self.last_name = random.choice([
|
||||
"Smith", "Johnson", "Williams", "Brown", "Jones", "Garcia", "Miller", "Davis",
|
||||
"Anderson", "Wilson", "Taylor", "Thomas", "Moore", "Martin", "Jackson", "Lee",
|
||||
"Thompson", "White", "Harris", "Clark", "Lewis", "Walker", "Hall", "Young"
|
||||
])
|
||||
|
||||
# Modify first letter of first name
|
||||
new_first_letter = random.choice("ABCDEFGHIJKLMNOPQRSTUVWXYZ")
|
||||
self.first_name = new_first_letter + first_name[1:]
|
||||
|
||||
print(f"\n{Fore.CYAN}{EMOJI['PASSWORD']} {self.translator.get('register.password')}: {self.password} {Style.RESET_ALL}")
|
||||
print(f"{Fore.CYAN}{EMOJI['FORM']} {self.translator.get('register.first_name')}: {self.first_name} {Style.RESET_ALL}")
|
||||
print(f"{Fore.CYAN}{EMOJI['FORM']} {self.translator.get('register.last_name')}: {self.last_name} {Style.RESET_ALL}")
|
||||
|
||||
def _generate_password(self, length=12):
|
||||
"""Generate Random Password"""
|
||||
chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!@#$%^&*"
|
||||
return ''.join(random.choices(chars, k=length))
|
||||
|
||||
def setup_email(self):
|
||||
"""Setup Email"""
|
||||
try:
|
||||
print(f"{Fore.CYAN}{EMOJI['START']} {self.translator.get('register.manual_email_input') if self.translator else 'Please enter your email address:'}")
|
||||
self.email_address = input().strip()
|
||||
|
||||
if '@' not in self.email_address:
|
||||
print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('register.invalid_email') if self.translator else '无效的邮箱地址'}{Style.RESET_ALL}")
|
||||
return False
|
||||
|
||||
print(f"{Fore.CYAN}{EMOJI['MAIL']} {self.translator.get('register.email_address')}: {self.email_address}" + "\n" + f"{Style.RESET_ALL}")
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('register.email_setup_failed', error=str(e))}{Style.RESET_ALL}")
|
||||
return False
|
||||
|
||||
def get_verification_code(self):
|
||||
"""Manually Get Verification Code"""
|
||||
try:
|
||||
print(f"{Fore.CYAN}{EMOJI['CODE']} {self.translator.get('register.manual_code_input') if self.translator else 'Please enter the verification code:'}")
|
||||
code = input().strip()
|
||||
|
||||
if not code.isdigit() or len(code) != 6:
|
||||
print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('register.invalid_code') if self.translator else '无效的验证码'}{Style.RESET_ALL}")
|
||||
return None
|
||||
|
||||
return code
|
||||
|
||||
except Exception as e:
|
||||
print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('register.code_input_failed', error=str(e))}{Style.RESET_ALL}")
|
||||
return None
|
||||
|
||||
def register_cursor(self):
|
||||
"""Register Cursor"""
|
||||
browser_tab = None
|
||||
try:
|
||||
print(f"{Fore.CYAN}{EMOJI['START']} {self.translator.get('register.register_start')}...{Style.RESET_ALL}")
|
||||
|
||||
# Use new_signup.py directly for registration
|
||||
from new_signup import main as new_signup_main
|
||||
|
||||
# Execute new registration process, passing 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=None, # No email tab needed
|
||||
controller=self, # Pass self instead of self.controller
|
||||
translator=self.translator
|
||||
)
|
||||
|
||||
if result:
|
||||
# Use the returned browser instance to get account information
|
||||
self.signup_tab = browser_tab # Save browser instance
|
||||
success = self._get_account_info()
|
||||
|
||||
# Close browser after getting information
|
||||
if browser_tab:
|
||||
try:
|
||||
browser_tab.quit()
|
||||
except:
|
||||
pass
|
||||
|
||||
return success
|
||||
|
||||
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:
|
||||
# Ensure browser is closed in any case
|
||||
if browser_tab:
|
||||
try:
|
||||
browser_tab.quit()
|
||||
except:
|
||||
pass
|
||||
|
||||
def _get_account_info(self):
|
||||
"""Get Account Information and Token"""
|
||||
try:
|
||||
self.signup_tab.get(self.settings_url)
|
||||
time.sleep(2)
|
||||
|
||||
usage_selector = (
|
||||
"css:div.col-span-2 > div > div > div > div > "
|
||||
"div:nth-child(1) > div.flex.items-center.justify-between.gap-2 > "
|
||||
"span.font-mono.text-sm\\/\\[0\\.875rem\\]"
|
||||
)
|
||||
usage_ele = self.signup_tab.ele(usage_selector)
|
||||
total_usage = "未知"
|
||||
if usage_ele:
|
||||
total_usage = usage_ele.text.split("/")[-1].strip()
|
||||
|
||||
print(f"Total Usage: {total_usage}\n")
|
||||
print(f"{Fore.CYAN}{EMOJI['WAIT']} {self.translator.get('register.get_token')}...{Style.RESET_ALL}")
|
||||
max_attempts = 30
|
||||
retry_interval = 2
|
||||
attempts = 0
|
||||
|
||||
while attempts < max_attempts:
|
||||
try:
|
||||
cookies = self.signup_tab.cookies()
|
||||
for cookie in cookies:
|
||||
if cookie.get("name") == "WorkosCursorSessionToken":
|
||||
token = get_token_from_cookie(cookie["value"], self.translator)
|
||||
print(f"{Fore.GREEN}{EMOJI['SUCCESS']} {self.translator.get('register.token_success')}{Style.RESET_ALL}")
|
||||
self._save_account_info(token, total_usage)
|
||||
return True
|
||||
|
||||
attempts += 1
|
||||
if attempts < max_attempts:
|
||||
print(f"{Fore.YELLOW}{EMOJI['WAIT']} {self.translator.get('register.token_attempt', attempt=attempts, time=retry_interval)}{Style.RESET_ALL}")
|
||||
time.sleep(retry_interval)
|
||||
else:
|
||||
print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('register.token_max_attempts', max=max_attempts)}{Style.RESET_ALL}")
|
||||
|
||||
except Exception as e:
|
||||
print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('register.token_failed', error=str(e))}{Style.RESET_ALL}")
|
||||
attempts += 1
|
||||
if attempts < max_attempts:
|
||||
print(f"{Fore.YELLOW}{EMOJI['WAIT']} {self.translator.get('register.token_attempt', attempt=attempts, time=retry_interval)}{Style.RESET_ALL}")
|
||||
time.sleep(retry_interval)
|
||||
|
||||
return False
|
||||
|
||||
except Exception as e:
|
||||
print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('register.account_error', error=str(e))}{Style.RESET_ALL}")
|
||||
return False
|
||||
|
||||
def _save_account_info(self, token, total_usage):
|
||||
"""Save Account Information to File"""
|
||||
try:
|
||||
# Update authentication information first
|
||||
print(f"{Fore.CYAN}{EMOJI['KEY']} {self.translator.get('register.update_cursor_auth_info')}...{Style.RESET_ALL}")
|
||||
if self.update_cursor_auth(email=self.email_address, access_token=token, refresh_token=token):
|
||||
print(f"{Fore.GREEN}{EMOJI['SUCCESS']} {self.translator.get('register.cursor_auth_info_updated')}...{Style.RESET_ALL}")
|
||||
else:
|
||||
print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('register.cursor_auth_info_update_failed')}...{Style.RESET_ALL}")
|
||||
|
||||
# Reset machine ID
|
||||
print(f"{Fore.CYAN}{EMOJI['UPDATE']} {self.translator.get('register.reset_machine_id')}...{Style.RESET_ALL}")
|
||||
resetter = MachineIDResetter(self.translator) # Create instance with translator
|
||||
if not resetter.reset_machine_ids(): # Call reset_machine_ids method directly
|
||||
raise Exception("Failed to reset machine ID")
|
||||
|
||||
# Save account information to file
|
||||
with open('cursor_accounts.txt', 'a', encoding='utf-8') as f:
|
||||
f.write(f"\n{'='*50}\n")
|
||||
f.write(f"Email: {self.email_address}\n")
|
||||
f.write(f"Password: {self.password}\n")
|
||||
f.write(f"Token: {token}\n")
|
||||
f.write(f"Usage Limit: {total_usage}\n")
|
||||
f.write(f"{'='*50}\n")
|
||||
|
||||
print(f"{Fore.GREEN}{EMOJI['SUCCESS']} {self.translator.get('register.account_info_saved')}...{Style.RESET_ALL}")
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('register.save_account_info_failed', error=str(e))}{Style.RESET_ALL}")
|
||||
return False
|
||||
|
||||
def start(self):
|
||||
"""Start Registration Process"""
|
||||
try:
|
||||
if self.setup_email():
|
||||
if self.register_cursor():
|
||||
print(f"\n{Fore.GREEN}{EMOJI['DONE']} {self.translator.get('register.cursor_registration_completed')}...{Style.RESET_ALL}")
|
||||
return True
|
||||
return False
|
||||
finally:
|
||||
# Close email tab
|
||||
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):
|
||||
"""Convenient function to update Cursor authentication information"""
|
||||
auth_manager = CursorAuth(translator=self.translator)
|
||||
return auth_manager.update_auth(email, access_token, refresh_token)
|
||||
|
||||
def main(translator=None):
|
||||
"""Main function to be called from main.py"""
|
||||
print(f"\n{Fore.CYAN}{'='*50}{Style.RESET_ALL}")
|
||||
print(f"{Fore.CYAN}{EMOJI['START']} {translator.get('register.title')}{Style.RESET_ALL}")
|
||||
print(f"{Fore.CYAN}{'='*50}{Style.RESET_ALL}")
|
||||
|
||||
registration = CursorRegistration(translator)
|
||||
registration.start()
|
||||
|
||||
print(f"\n{Fore.CYAN}{'='*50}{Style.RESET_ALL}")
|
||||
input(f"{EMOJI['INFO']} {translator.get('register.press_enter')}...")
|
||||
|
||||
if __name__ == "__main__":
|
||||
from main import translator as main_translator
|
||||
main(main_translator)
|
@ -1,386 +0,0 @@
|
||||
from oauth_auth import OAuthHandler
|
||||
import time
|
||||
from colorama import Fore, Style, init
|
||||
import sys
|
||||
|
||||
# Initialize colorama
|
||||
init()
|
||||
|
||||
# Define emoji constants
|
||||
EMOJI = {
|
||||
'START': '🚀',
|
||||
'DELETE': '🗑️',
|
||||
'SUCCESS': '✅',
|
||||
'ERROR': '❌',
|
||||
'WAIT': '⏳',
|
||||
'INFO': 'ℹ️',
|
||||
'WARNING': '⚠️'
|
||||
}
|
||||
|
||||
class CursorGoogleAccountDeleter(OAuthHandler):
|
||||
def __init__(self, translator=None):
|
||||
super().__init__(translator, auth_type='google')
|
||||
|
||||
def delete_google_account(self):
|
||||
"""Delete Cursor account using Google OAuth"""
|
||||
try:
|
||||
# Setup browser and select profile
|
||||
if not self.setup_browser():
|
||||
return False
|
||||
|
||||
print(f"{Fore.CYAN}{EMOJI['INFO']} {self.translator.get('account_delete.starting_process') if self.translator else 'Starting account deletion process...'}{Style.RESET_ALL}")
|
||||
|
||||
# Navigate to Cursor auth page - using the same URL as in registration
|
||||
self.browser.get("https://authenticator.cursor.sh/sign-up")
|
||||
time.sleep(2)
|
||||
|
||||
# Click Google auth button using same selectors as in registration
|
||||
selectors = [
|
||||
"//a[contains(@href,'GoogleOAuth')]",
|
||||
"//a[contains(@class,'auth-method-button') and contains(@href,'GoogleOAuth')]",
|
||||
"(//a[contains(@class,'auth-method-button')])[1]" # First auth button as fallback
|
||||
]
|
||||
|
||||
auth_btn = None
|
||||
for selector in selectors:
|
||||
try:
|
||||
auth_btn = self.browser.ele(f"xpath:{selector}", timeout=2)
|
||||
if auth_btn:
|
||||
break
|
||||
except:
|
||||
continue
|
||||
|
||||
if not auth_btn:
|
||||
raise Exception(self.translator.get('account_delete.google_button_not_found') if self.translator else "Google login button not found")
|
||||
|
||||
print(f"{Fore.CYAN}{EMOJI['INFO']} {self.translator.get('account_delete.logging_in') if self.translator else 'Logging in with Google...'}{Style.RESET_ALL}")
|
||||
auth_btn.click()
|
||||
|
||||
# Wait for authentication to complete using a more robust method
|
||||
print(f"{Fore.CYAN}{EMOJI['WAIT']} {self.translator.get('account_delete.waiting_for_auth', fallback='Waiting for Google authentication...')}{Style.RESET_ALL}")
|
||||
|
||||
# Dynamic wait for authentication
|
||||
max_wait_time = 120 # Increase maximum wait time to 120 seconds
|
||||
start_time = time.time()
|
||||
check_interval = 3 # Check every 3 seconds
|
||||
google_account_alert_shown = False # Track if we've shown the alert already
|
||||
|
||||
while time.time() - start_time < max_wait_time:
|
||||
current_url = self.browser.url
|
||||
|
||||
# If we're already on the settings or dashboard page, we're successful
|
||||
if "/dashboard" in current_url or "/settings" in current_url or "cursor.com" in current_url:
|
||||
print(f"{Fore.GREEN}{EMOJI['SUCCESS']} {self.translator.get('account_delete.login_successful') if self.translator else 'Login successful'}{Style.RESET_ALL}")
|
||||
break
|
||||
|
||||
# If we're on Google accounts page or accounts.google.com, wait for user selection
|
||||
if "accounts.google.com" in current_url:
|
||||
# Only show the alert once to avoid spamming
|
||||
if not google_account_alert_shown:
|
||||
print(f"{Fore.CYAN}{EMOJI['INFO']} {self.translator.get('account_delete.select_google_account', fallback='Please select your Google account...')}{Style.RESET_ALL}")
|
||||
# Alert to indicate user action needed
|
||||
try:
|
||||
self.browser.run_js("""
|
||||
alert('Please select your Google account to continue with Cursor authentication');
|
||||
""")
|
||||
google_account_alert_shown = True # Mark that we've shown the alert
|
||||
except:
|
||||
pass # Alert is optional
|
||||
|
||||
# Sleep before checking again
|
||||
time.sleep(check_interval)
|
||||
else:
|
||||
# If the loop completed without breaking, it means we hit the timeout
|
||||
print(f"{Fore.YELLOW}{EMOJI['WARNING']} {self.translator.get('account_delete.auth_timeout', fallback='Authentication timeout, continuing anyway...')}{Style.RESET_ALL}")
|
||||
|
||||
# Check current URL to determine next steps
|
||||
current_url = self.browser.url
|
||||
|
||||
# If we're already on the settings page, no need to navigate
|
||||
if "/settings" in current_url and "cursor.com" in current_url:
|
||||
print(f"{Fore.GREEN}{EMOJI['SUCCESS']} {self.translator.get('account_delete.already_on_settings', fallback='Already on settings page')}{Style.RESET_ALL}")
|
||||
# If we're on the dashboard or any Cursor page but not settings, navigate to settings
|
||||
elif "cursor.com" in current_url or "authenticator.cursor.sh" in current_url:
|
||||
print(f"{Fore.CYAN}{EMOJI['INFO']} {self.translator.get('account_delete.navigating_to_settings', fallback='Navigating to settings page...')}{Style.RESET_ALL}")
|
||||
self.browser.get("https://www.cursor.com/settings")
|
||||
# If we're still on Google auth or somewhere else, try directly going to settings
|
||||
else:
|
||||
print(f"{Fore.YELLOW}{EMOJI['WARNING']} {self.translator.get('account_delete.login_redirect_failed', fallback='Login redirection failed, trying direct navigation...')}{Style.RESET_ALL}")
|
||||
self.browser.get("https://www.cursor.com/settings")
|
||||
|
||||
# Wait for the settings page to load
|
||||
time.sleep(3) # Reduced from 5 seconds
|
||||
|
||||
# First look for the email element to confirm we're logged in
|
||||
try:
|
||||
email_element = self.browser.ele("css:div[class='flex w-full flex-col gap-2'] div:nth-child(2) p:nth-child(2)")
|
||||
if email_element:
|
||||
email = email_element.text
|
||||
print(f"{Fore.CYAN}{EMOJI['INFO']} {self.translator.get('account_delete.found_email', email=email, fallback=f'Found email: {email}')}{Style.RESET_ALL}")
|
||||
except Exception as e:
|
||||
print(f"{Fore.YELLOW}{EMOJI['WARNING']} {self.translator.get('account_delete.email_not_found', error=str(e), fallback=f'Email not found: {str(e)}')}{Style.RESET_ALL}")
|
||||
|
||||
# Click on "Advanced" tab or dropdown - keep only the successful approach
|
||||
advanced_found = False
|
||||
|
||||
# Direct JavaScript querySelector approach that worked according to logs
|
||||
try:
|
||||
advanced_element_js = self.browser.run_js("""
|
||||
// Try to find the Advanced dropdown using querySelector with the exact classes
|
||||
let advancedElement = document.querySelector('div.mb-0.flex.cursor-pointer.items-center.text-xs:not([style*="display: none"])');
|
||||
|
||||
// If not found, try a more general approach
|
||||
if (!advancedElement) {
|
||||
const allDivs = document.querySelectorAll('div');
|
||||
for (const div of allDivs) {
|
||||
if (div.textContent.includes('Advanced') &&
|
||||
div.className.includes('mb-0') &&
|
||||
div.className.includes('flex') &&
|
||||
div.className.includes('cursor-pointer')) {
|
||||
advancedElement = div;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Click the element if found
|
||||
if (advancedElement) {
|
||||
advancedElement.click();
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
""")
|
||||
|
||||
if advanced_element_js:
|
||||
print(f"{Fore.GREEN}{EMOJI['SUCCESS']} {self.translator.get('account_delete.advanced_tab_clicked', fallback='Found and clicked Advanced using direct JavaScript selector')}{Style.RESET_ALL}")
|
||||
advanced_found = True
|
||||
time.sleep(1) # Reduced from 2 seconds
|
||||
except Exception as e:
|
||||
print(f"{Fore.YELLOW}{EMOJI['WARNING']} {self.translator.get('account_delete.advanced_tab_error', error=str(e), fallback='JavaScript querySelector approach failed: {str(e)}')}{Style.RESET_ALL}")
|
||||
|
||||
if not advanced_found:
|
||||
# Fallback to direct URL navigation which is faster and more reliable
|
||||
try:
|
||||
self.browser.get("https://www.cursor.com/settings?tab=advanced")
|
||||
print(f"{Fore.YELLOW}{EMOJI['INFO']} {self.translator.get('account_delete.direct_advanced_navigation', fallback='Trying direct navigation to advanced tab')}{Style.RESET_ALL}")
|
||||
advanced_found = True
|
||||
except:
|
||||
raise Exception(self.translator.get('account_delete.advanced_tab_not_found') if self.translator else "Advanced option not found after multiple attempts")
|
||||
|
||||
# Wait for dropdown/tab content to load
|
||||
time.sleep(2) # Reduced from 4 seconds
|
||||
|
||||
# Find and click the "Delete Account" button
|
||||
delete_button_found = False
|
||||
|
||||
# Simplified approach for delete button based on what worked
|
||||
delete_button_selectors = [
|
||||
'xpath://button[contains(., "Delete Account")]',
|
||||
'xpath://button[text()="Delete Account"]',
|
||||
'xpath://div[contains(text(), "Delete Account")]',
|
||||
'xpath://button[contains(text(), "Delete") and contains(text(), "Account")]'
|
||||
]
|
||||
|
||||
for selector in delete_button_selectors:
|
||||
try:
|
||||
delete_button = self.browser.ele(selector, timeout=2)
|
||||
if delete_button:
|
||||
delete_button.click()
|
||||
print(f"{Fore.CYAN}{EMOJI['INFO']} {self.translator.get('account_delete.delete_button_clicked') if self.translator else 'Clicked on Delete Account button'}{Style.RESET_ALL}")
|
||||
delete_button_found = True
|
||||
break
|
||||
except:
|
||||
continue
|
||||
|
||||
if not delete_button_found:
|
||||
raise Exception(self.translator.get('account_delete.delete_button_not_found') if self.translator else "Delete Account button not found")
|
||||
|
||||
# Wait for confirmation dialog to appear
|
||||
time.sleep(2)
|
||||
|
||||
# Check if we need to input "Delete" at all - some modals might not require it
|
||||
input_required = True
|
||||
try:
|
||||
# Try detecting if the DELETE button is already enabled
|
||||
delete_button_enabled = self.browser.run_js("""
|
||||
const buttons = Array.from(document.querySelectorAll('button'));
|
||||
const deleteButtons = buttons.filter(btn =>
|
||||
btn.textContent.trim() === 'DELETE' ||
|
||||
btn.textContent.trim() === 'Delete'
|
||||
);
|
||||
|
||||
if (deleteButtons.length > 0) {
|
||||
return !deleteButtons.some(btn => btn.disabled);
|
||||
}
|
||||
return false;
|
||||
""")
|
||||
|
||||
if delete_button_enabled:
|
||||
print(f"{Fore.CYAN}{EMOJI['INFO']} DELETE button appears to be enabled already. Input may not be required.{Style.RESET_ALL}")
|
||||
input_required = False
|
||||
except:
|
||||
pass
|
||||
|
||||
# Type "Delete" in the confirmation input - only if required
|
||||
delete_input_found = False
|
||||
|
||||
if input_required:
|
||||
# Try common selectors for the input field
|
||||
delete_input_selectors = [
|
||||
'xpath://input[@placeholder="Delete"]',
|
||||
'xpath://div[contains(@class, "modal")]//input',
|
||||
'xpath://input',
|
||||
'css:input'
|
||||
]
|
||||
|
||||
for selector in delete_input_selectors:
|
||||
try:
|
||||
delete_input = self.browser.ele(selector, timeout=3)
|
||||
if delete_input:
|
||||
delete_input.clear()
|
||||
delete_input.input("Delete")
|
||||
print(f"{Fore.GREEN}{EMOJI['SUCCESS']} {self.translator.get('account_delete.typed_delete', fallback='Typed \"Delete\" in confirmation box')}{Style.RESET_ALL}")
|
||||
delete_input_found = True
|
||||
time.sleep(2)
|
||||
break
|
||||
except:
|
||||
# Try direct JavaScript input as fallback
|
||||
try:
|
||||
self.browser.run_js(r"""
|
||||
arguments[0].value = "Delete";
|
||||
const event = new Event('input', { bubbles: true });
|
||||
arguments[0].dispatchEvent(event);
|
||||
const changeEvent = new Event('change', { bubbles: true });
|
||||
arguments[0].dispatchEvent(changeEvent);
|
||||
""", delete_input)
|
||||
print(f"{Fore.GREEN}{EMOJI['SUCCESS']} {self.translator.get('account_delete.typed_delete_js', fallback='Typed \"Delete\" using JavaScript')}{Style.RESET_ALL}")
|
||||
delete_input_found = True
|
||||
time.sleep(2)
|
||||
break
|
||||
except:
|
||||
continue
|
||||
|
||||
if not delete_input_found:
|
||||
print(f"{Fore.YELLOW}{EMOJI['WARNING']} {self.translator.get('account_delete.delete_input_not_found', fallback='Delete confirmation input not found, continuing anyway')}{Style.RESET_ALL}")
|
||||
time.sleep(2)
|
||||
|
||||
# Wait before clicking the final DELETE button
|
||||
time.sleep(2)
|
||||
|
||||
# Click on the final DELETE button
|
||||
confirm_button_found = False
|
||||
|
||||
# Use JavaScript approach for the DELETE button
|
||||
try:
|
||||
delete_button_js = self.browser.run_js("""
|
||||
// Try to find the DELETE button by exact text content
|
||||
const buttons = Array.from(document.querySelectorAll('button'));
|
||||
const deleteButton = buttons.find(btn =>
|
||||
btn.textContent.trim() === 'DELETE' ||
|
||||
btn.textContent.trim() === 'Delete'
|
||||
);
|
||||
|
||||
if (deleteButton) {
|
||||
console.log("Found DELETE button with JavaScript");
|
||||
deleteButton.click();
|
||||
return true;
|
||||
}
|
||||
|
||||
// If not found by text, try to find right-most button in the modal
|
||||
const modalButtons = Array.from(document.querySelectorAll('.relative button, [role="dialog"] button, .modal button, [aria-modal="true"] button'));
|
||||
|
||||
if (modalButtons.length > 1) {
|
||||
modalButtons.sort((a, b) => {
|
||||
const rectA = a.getBoundingClientRect();
|
||||
const rectB = b.getBoundingClientRect();
|
||||
return rectB.right - rectA.right;
|
||||
});
|
||||
|
||||
console.log("Clicking right-most button in modal");
|
||||
modalButtons[0].click();
|
||||
return true;
|
||||
} else if (modalButtons.length === 1) {
|
||||
console.log("Clicking single button found in modal");
|
||||
modalButtons[0].click();
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
""")
|
||||
|
||||
if delete_button_js:
|
||||
print(f"{Fore.GREEN}{EMOJI['SUCCESS']} {self.translator.get('account_delete.delete_button_clicked', fallback='Clicked DELETE button')}{Style.RESET_ALL}")
|
||||
confirm_button_found = True
|
||||
except:
|
||||
pass
|
||||
|
||||
if not confirm_button_found:
|
||||
# Fallback to simple selectors
|
||||
delete_button_selectors = [
|
||||
'xpath://button[text()="DELETE"]',
|
||||
'xpath://div[contains(@class, "modal")]//button[last()]'
|
||||
]
|
||||
|
||||
for selector in delete_button_selectors:
|
||||
try:
|
||||
delete_button = self.browser.ele(selector, timeout=2)
|
||||
if delete_button:
|
||||
delete_button.click()
|
||||
print(f"{Fore.GREEN}{EMOJI['SUCCESS']} {self.translator.get('account_delete.delete_button_clicked', fallback='Account deleted successfully!')}{Style.RESET_ALL}")
|
||||
confirm_button_found = True
|
||||
break
|
||||
except:
|
||||
continue
|
||||
|
||||
if not confirm_button_found:
|
||||
raise Exception(self.translator.get('account_delete.confirm_button_not_found') if self.translator else "Confirm button not found")
|
||||
|
||||
# Wait a moment to see the confirmation
|
||||
time.sleep(2)
|
||||
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('account_delete.error', error=str(e)) if self.translator else f'Error during account deletion: {str(e)}'}{Style.RESET_ALL}")
|
||||
return False
|
||||
finally:
|
||||
# Clean up browser
|
||||
if self.browser:
|
||||
try:
|
||||
self.browser.quit()
|
||||
except:
|
||||
pass
|
||||
|
||||
def main(translator=None):
|
||||
"""Main function to handle Google account deletion"""
|
||||
print(f"\n{Fore.CYAN}{EMOJI['START']} {translator.get('account_delete.title') if translator else 'Cursor Google Account Deletion Tool'}{Style.RESET_ALL}")
|
||||
print(f"{Fore.YELLOW}{'─' * 50}{Style.RESET_ALL}")
|
||||
|
||||
deleter = CursorGoogleAccountDeleter(translator)
|
||||
|
||||
try:
|
||||
# Ask for confirmation
|
||||
print(f"{Fore.RED}{EMOJI['WARNING']} {translator.get('account_delete.warning') if translator else 'WARNING: This will permanently delete your Cursor account. This action cannot be undone.'}{Style.RESET_ALL}")
|
||||
confirm = input(f"{Fore.RED} {translator.get('account_delete.confirm_prompt') if translator else 'Are you sure you want to proceed? (y/N): '}{Style.RESET_ALL}").lower()
|
||||
|
||||
if confirm != 'y':
|
||||
print(f"{Fore.YELLOW}{EMOJI['INFO']} {translator.get('account_delete.cancelled') if translator else 'Account deletion cancelled.'}{Style.RESET_ALL}")
|
||||
return
|
||||
|
||||
success = deleter.delete_google_account()
|
||||
|
||||
if success:
|
||||
print(f"\n{Fore.GREEN}{EMOJI['SUCCESS']} {translator.get('account_delete.success') if translator else 'Your Cursor account has been successfully deleted!'}{Style.RESET_ALL}")
|
||||
else:
|
||||
print(f"\n{Fore.RED}{EMOJI['ERROR']} {translator.get('account_delete.failed') if translator else 'Account deletion process failed or was cancelled.'}{Style.RESET_ALL}")
|
||||
|
||||
except KeyboardInterrupt:
|
||||
print(f"\n{Fore.YELLOW}{EMOJI['INFO']} {translator.get('account_delete.interrupted') if translator else 'Account deletion process interrupted by user.'}{Style.RESET_ALL}")
|
||||
except Exception as e:
|
||||
print(f"{Fore.RED}{EMOJI['ERROR']} {translator.get('account_delete.unexpected_error', error=str(e)) if translator else f'Unexpected error: {str(e)}'}{Style.RESET_ALL}")
|
||||
finally:
|
||||
print(f"{Fore.YELLOW}{'─' * 50}{Style.RESET_ALL}")
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
@ -1,701 +0,0 @@
|
||||
import os
|
||||
import time
|
||||
import uuid
|
||||
import json
|
||||
import random
|
||||
import string
|
||||
import requests
|
||||
from selenium import webdriver
|
||||
from selenium.webdriver.common.by import By
|
||||
from selenium.webdriver.chrome.service import Service
|
||||
from selenium.webdriver.chrome.options import Options
|
||||
from selenium.webdriver.support.ui import WebDriverWait
|
||||
from selenium.webdriver.support import expected_conditions as EC
|
||||
from webdriver_manager.chrome import ChromeDriverManager
|
||||
import logging
|
||||
import platform
|
||||
from colorama import Fore, Style, init
|
||||
from selenium.common.exceptions import TimeoutException, WebDriverException, NoSuchElementException
|
||||
import shutil
|
||||
|
||||
# Initialize colorama
|
||||
init()
|
||||
|
||||
# Set up logging
|
||||
logging.basicConfig(level=logging.INFO, format="%(asctime)s - %(levelname)s - %(message)s")
|
||||
|
||||
# Define emoji constants
|
||||
EMOJI = {
|
||||
'START': '🚀',
|
||||
'FORM': '📝',
|
||||
'VERIFY': '🔄',
|
||||
'PASSWORD': '🔑',
|
||||
'CODE': '📱',
|
||||
'DONE': '✨',
|
||||
'ERROR': '❌',
|
||||
'WAIT': '⏳',
|
||||
'SUCCESS': '✅',
|
||||
'MAIL': '📧',
|
||||
'KEY': '🔐',
|
||||
'UPDATE': '🔄',
|
||||
'INFO': 'ℹ️',
|
||||
'EMAIL': '📧',
|
||||
'REFRESH': '🔄',
|
||||
'LINK': '🔗',
|
||||
'WARNING': '⚠️'
|
||||
}
|
||||
|
||||
class GitHubCursorRegistration:
|
||||
def __init__(self, translator=None):
|
||||
self.translator = translator
|
||||
# Set browser to visible mode
|
||||
os.environ['BROWSER_HEADLESS'] = 'False'
|
||||
self.browser = None
|
||||
self.email_address = None
|
||||
|
||||
# Generate random credentials
|
||||
self.github_username = ''.join(random.choices(string.ascii_lowercase + string.digits, k=10))
|
||||
self.github_password = ''.join(random.choices(string.ascii_letters + string.digits + string.punctuation, k=16))
|
||||
|
||||
def setup_browser(self):
|
||||
"""Setup and configure the web browser"""
|
||||
try:
|
||||
print(f"{Fore.CYAN}{EMOJI['START']} Setting up browser...{Style.RESET_ALL}")
|
||||
|
||||
options = Options()
|
||||
options.add_argument('--incognito')
|
||||
options.add_argument('--no-sandbox')
|
||||
options.add_argument('--disable-dev-shm-usage')
|
||||
options.add_argument('--window-size=1920,1080')
|
||||
options.add_argument('--disable-notifications')
|
||||
options.add_argument('--user-agent=Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.110 Safari/537.36')
|
||||
|
||||
self.browser = webdriver.Chrome(service=Service(ChromeDriverManager().install()), options=options)
|
||||
self.browser.set_page_load_timeout(30)
|
||||
return True
|
||||
except Exception as e:
|
||||
print(f"{Fore.RED}{EMOJI['ERROR']} Failed to setup browser: {str(e)}{Style.RESET_ALL}")
|
||||
return False
|
||||
|
||||
def get_temp_email(self):
|
||||
"""Get a temporary email address using YOPmail"""
|
||||
try:
|
||||
if not self.browser:
|
||||
if not self.setup_browser():
|
||||
return False
|
||||
|
||||
print(f"{Fore.CYAN}{EMOJI['MAIL']} Generating temporary email address...{Style.RESET_ALL}")
|
||||
self.browser.get("https://yopmail.com/")
|
||||
time.sleep(2)
|
||||
|
||||
# Generate a realistic username
|
||||
first_names = ["john", "sara", "michael", "emma", "david", "jennifer", "robert", "lisa"]
|
||||
last_names = ["smith", "johnson", "williams", "brown", "jones", "miller", "davis", "garcia"]
|
||||
|
||||
random_first = random.choice(first_names)
|
||||
random_last = random.choice(last_names)
|
||||
random_num = random.randint(100, 999)
|
||||
|
||||
username = f"{random_first}.{random_last}{random_num}"
|
||||
|
||||
# Enter the username and check inbox
|
||||
email_field = self.browser.find_element(By.XPATH, "//input[@id='login']")
|
||||
if email_field:
|
||||
email_field.clear()
|
||||
email_field.send_keys(username)
|
||||
time.sleep(1)
|
||||
|
||||
# Click the check button
|
||||
check_button = self.browser.find_element(By.XPATH, "//button[@title='Check Inbox' or @class='sbut' or contains(@onclick, 'ver')]")
|
||||
if check_button:
|
||||
check_button.click()
|
||||
time.sleep(2)
|
||||
self.email_address = f"{username}@yopmail.com"
|
||||
print(f"{Fore.GREEN}{EMOJI['SUCCESS']} Temp email created: {self.email_address}{Style.RESET_ALL}")
|
||||
return True
|
||||
|
||||
print(f"{Fore.RED}{EMOJI['ERROR']} Failed to create YOPmail address{Style.RESET_ALL}")
|
||||
return False
|
||||
|
||||
except Exception as e:
|
||||
print(f"{Fore.RED}{EMOJI['ERROR']} Error getting temporary email: {str(e)}{Style.RESET_ALL}")
|
||||
return False
|
||||
|
||||
def register_github(self):
|
||||
"""Register a new GitHub account"""
|
||||
if not self.email_address:
|
||||
print(f"{Fore.RED}{EMOJI['ERROR']} No email address available{Style.RESET_ALL}")
|
||||
return False
|
||||
|
||||
if not self.browser:
|
||||
if not self.setup_browser():
|
||||
return False
|
||||
|
||||
try:
|
||||
print(f"{Fore.CYAN}{EMOJI['FORM']} Registering GitHub account...{Style.RESET_ALL}")
|
||||
self.browser.get("https://github.com/join")
|
||||
time.sleep(3)
|
||||
|
||||
# Fill in the registration form
|
||||
WebDriverWait(self.browser, 15).until(EC.visibility_of_element_located((By.ID, "user_login")))
|
||||
self.browser.find_element(By.ID, "user_login").send_keys(self.github_username)
|
||||
self.browser.find_element(By.ID, "user_email").send_keys(self.email_address)
|
||||
self.browser.find_element(By.ID, "user_password").send_keys(self.github_password)
|
||||
|
||||
print(f"{Fore.CYAN}{EMOJI['INFO']} GitHub username: {self.github_username}{Style.RESET_ALL}")
|
||||
print(f"{Fore.CYAN}{EMOJI['INFO']} GitHub password: {self.github_password}{Style.RESET_ALL}")
|
||||
|
||||
# Check for any notice or popup and handle it
|
||||
try:
|
||||
signup_button = self.browser.find_element(By.ID, "signup_button")
|
||||
print(f"{Fore.CYAN}{EMOJI['INFO']} Clicking sign up button...{Style.RESET_ALL}")
|
||||
signup_button.click()
|
||||
except NoSuchElementException:
|
||||
print(f"{Fore.YELLOW}{EMOJI['INFO']} Signup button not found, trying alternative selector{Style.RESET_ALL}")
|
||||
buttons = self.browser.find_elements(By.TAG_NAME, "button")
|
||||
for button in buttons:
|
||||
if "Sign up" in button.text:
|
||||
button.click()
|
||||
break
|
||||
|
||||
# Wait for page transition and check for CAPTCHA
|
||||
time.sleep(5)
|
||||
|
||||
# Check if registration was successful or if CAPTCHA appeared
|
||||
current_url = self.browser.current_url
|
||||
|
||||
# Look for CAPTCHA in URL or on page
|
||||
if "captcha" in current_url.lower() or "are you a robot" in self.browser.page_source.lower():
|
||||
print(f"{Fore.YELLOW}{EMOJI['WAIT']} CAPTCHA detected, please complete it manually{Style.RESET_ALL}")
|
||||
print(f"{Fore.YELLOW}{EMOJI['INFO']} You have 60 seconds to solve the CAPTCHA...{Style.RESET_ALL}")
|
||||
|
||||
# Wait for user to solve CAPTCHA (60 seconds max)
|
||||
for i in range(60):
|
||||
current_url = self.browser.current_url
|
||||
if "captcha" not in current_url.lower() and "are you a robot" not in self.browser.page_source.lower():
|
||||
print(f"{Fore.GREEN}{EMOJI['SUCCESS']} CAPTCHA completed successfully{Style.RESET_ALL}")
|
||||
break
|
||||
time.sleep(1)
|
||||
if i % 10 == 0 and i > 0:
|
||||
print(f"{Fore.YELLOW}{EMOJI['WAIT']} Still waiting for CAPTCHA completion... {60-i} seconds remaining{Style.RESET_ALL}")
|
||||
|
||||
# Check if CAPTCHA was solved after waiting
|
||||
if "captcha" in self.browser.current_url.lower() or "are you a robot" in self.browser.page_source.lower():
|
||||
print(f"{Fore.RED}{EMOJI['ERROR']} CAPTCHA not solved within time limit{Style.RESET_ALL}")
|
||||
print(f"{Fore.YELLOW}{EMOJI['INFO']} Do you want more time to solve the CAPTCHA? (yes/no){Style.RESET_ALL}")
|
||||
response = input().lower().strip()
|
||||
if response in ['yes', 'y']:
|
||||
print(f"{Fore.YELLOW}{EMOJI['INFO']} Press Enter when you've completed the CAPTCHA...{Style.RESET_ALL}")
|
||||
input()
|
||||
if "captcha" in self.browser.current_url.lower() or "are you a robot" in self.browser.page_source.lower():
|
||||
print(f"{Fore.RED}{EMOJI['ERROR']} CAPTCHA still not solved{Style.RESET_ALL}")
|
||||
return False
|
||||
else:
|
||||
return False
|
||||
|
||||
# Wait for registration to complete
|
||||
time.sleep(5)
|
||||
|
||||
print(f"{Fore.GREEN}{EMOJI['SUCCESS']} GitHub account registered{Style.RESET_ALL}")
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
print(f"{Fore.RED}{EMOJI['ERROR']} Failed to register GitHub account: {str(e)}{Style.RESET_ALL}")
|
||||
return False
|
||||
|
||||
def check_email_verification(self):
|
||||
"""Check for GitHub verification email and click the verification link"""
|
||||
if not self.email_address or not self.browser:
|
||||
print(f"{Fore.RED}{EMOJI['ERROR']} Email or browser not available{Style.RESET_ALL}")
|
||||
return False
|
||||
|
||||
try:
|
||||
print(f"{Fore.CYAN}{EMOJI['EMAIL']} Checking for verification email...{Style.RESET_ALL}")
|
||||
|
||||
# Extract username from email for YOPmail
|
||||
username = self.email_address.split('@')[0]
|
||||
|
||||
max_attempts = 10
|
||||
for attempt in range(1, max_attempts + 1):
|
||||
print(f"{Fore.CYAN}{EMOJI['REFRESH']} Checking YOPmail inbox (attempt {attempt}/{max_attempts})...{Style.RESET_ALL}")
|
||||
|
||||
# Go to YOPmail inbox
|
||||
self.browser.get(f"https://yopmail.com/en/wm")
|
||||
time.sleep(2)
|
||||
|
||||
# Enter email address
|
||||
try:
|
||||
email_input = WebDriverWait(self.browser, 10).until(
|
||||
EC.presence_of_element_located((By.ID, "login"))
|
||||
)
|
||||
email_input.clear()
|
||||
email_input.send_keys(username)
|
||||
|
||||
# Click the check inbox button
|
||||
check_button = self.browser.find_element(By.CSS_SELECTOR, "button[onclick='verif()']")
|
||||
check_button.click()
|
||||
time.sleep(3)
|
||||
|
||||
# Switch to inbox frame
|
||||
iframe = WebDriverWait(self.browser, 10).until(
|
||||
EC.presence_of_element_located((By.ID, "ifinbox"))
|
||||
)
|
||||
self.browser.switch_to.frame(iframe)
|
||||
|
||||
# Look for GitHub email
|
||||
emails = self.browser.find_elements(By.CSS_SELECTOR, "div.m")
|
||||
github_email = None
|
||||
|
||||
for email in emails:
|
||||
if "github" in email.text.lower():
|
||||
github_email = email
|
||||
break
|
||||
|
||||
if github_email:
|
||||
print(f"{Fore.GREEN}{EMOJI['SUCCESS']} GitHub verification email found{Style.RESET_ALL}")
|
||||
github_email.click()
|
||||
time.sleep(2)
|
||||
|
||||
# Switch back to default content
|
||||
self.browser.switch_to.default_content()
|
||||
|
||||
# Switch to email content frame
|
||||
iframe = WebDriverWait(self.browser, 10).until(
|
||||
EC.presence_of_element_located((By.ID, "ifmail"))
|
||||
)
|
||||
self.browser.switch_to.frame(iframe)
|
||||
|
||||
# Find verification link
|
||||
try:
|
||||
# Look for the verification button or link
|
||||
verification_elements = self.browser.find_elements(By.XPATH, "//a[contains(text(), 'Verify') or contains(text(), 'verify') or contains(@href, 'verify')]")
|
||||
|
||||
if verification_elements:
|
||||
verification_link = verification_elements[0].get_attribute('href')
|
||||
print(f"{Fore.CYAN}{EMOJI['LINK']} Found verification link{Style.RESET_ALL}")
|
||||
|
||||
# Open the verification link in the same window
|
||||
self.browser.get(verification_link)
|
||||
time.sleep(5)
|
||||
|
||||
# Check if verification was successful
|
||||
if "verified" in self.browser.page_source.lower() or "successful" in self.browser.page_source.lower():
|
||||
print(f"{Fore.GREEN}{EMOJI['SUCCESS']} Email verified successfully{Style.RESET_ALL}")
|
||||
return True
|
||||
else:
|
||||
print(f"{Fore.YELLOW}{EMOJI['WARNING']} Email verification page loaded but success not confirmed{Style.RESET_ALL}")
|
||||
print(f"{Fore.YELLOW}{EMOJI['INFO']} Please check if verification was successful manually and press Enter to continue...{Style.RESET_ALL}")
|
||||
input()
|
||||
return True
|
||||
else:
|
||||
print(f"{Fore.RED}{EMOJI['ERROR']} No verification link found in email{Style.RESET_ALL}")
|
||||
except Exception as e:
|
||||
print(f"{Fore.RED}{EMOJI['ERROR']} Error extracting verification link: {str(e)}{Style.RESET_ALL}")
|
||||
else:
|
||||
print(f"{Fore.YELLOW}{EMOJI['WAIT']} No GitHub verification email yet, waiting... ({attempt}/{max_attempts}){Style.RESET_ALL}")
|
||||
time.sleep(15) # Wait before checking again
|
||||
|
||||
except Exception as e:
|
||||
print(f"{Fore.RED}{EMOJI['ERROR']} Error checking email: {str(e)}{Style.RESET_ALL}")
|
||||
|
||||
print(f"{Fore.RED}{EMOJI['ERROR']} No verification email received after {max_attempts} attempts{Style.RESET_ALL}")
|
||||
print(f"{Fore.YELLOW}{EMOJI['INFO']} Do you want to check manually? (yes/no){Style.RESET_ALL}")
|
||||
response = input().lower().strip()
|
||||
if response in ['yes', 'y']:
|
||||
print(f"{Fore.YELLOW}{EMOJI['INFO']} Please check your YOPmail inbox manually at: https://yopmail.com/en/wm")
|
||||
print(f"{Fore.YELLOW}{EMOJI['INFO']} Username: {username}")
|
||||
print(f"{Fore.YELLOW}{EMOJI['INFO']} Press Enter when you've verified the email...{Style.RESET_ALL}")
|
||||
input()
|
||||
return True
|
||||
return False
|
||||
|
||||
except Exception as e:
|
||||
print(f"{Fore.RED}{EMOJI['ERROR']} Failed to check verification email: {str(e)}{Style.RESET_ALL}")
|
||||
return False
|
||||
|
||||
def register_cursor(self):
|
||||
"""Register with Cursor using GitHub"""
|
||||
if not self.browser:
|
||||
if not self.setup_browser():
|
||||
return False
|
||||
|
||||
try:
|
||||
print(f"{Fore.CYAN}{EMOJI['KEY']} Registering with Cursor using GitHub...{Style.RESET_ALL}")
|
||||
|
||||
# Navigate to Cursor login page
|
||||
self.browser.get("https://cursor.sh/login")
|
||||
time.sleep(3)
|
||||
|
||||
try:
|
||||
# Look for GitHub login button
|
||||
github_buttons = WebDriverWait(self.browser, 15).until(
|
||||
EC.presence_of_all_elements_located((By.XPATH, "//button[contains(., 'GitHub') or contains(@class, 'github')]"))
|
||||
)
|
||||
|
||||
if not github_buttons:
|
||||
print(f"{Fore.RED}{EMOJI['ERROR']} GitHub login button not found{Style.RESET_ALL}")
|
||||
return False
|
||||
|
||||
# Click the first GitHub button
|
||||
print(f"{Fore.CYAN}{EMOJI['INFO']} Clicking GitHub login button...{Style.RESET_ALL}")
|
||||
github_buttons[0].click()
|
||||
time.sleep(5)
|
||||
|
||||
# Check if we're redirected to GitHub login
|
||||
current_url = self.browser.current_url
|
||||
if "github.com" in current_url:
|
||||
print(f"{Fore.CYAN}{EMOJI['INFO']} Redirected to GitHub login{Style.RESET_ALL}")
|
||||
|
||||
# Check if we need to log in to GitHub
|
||||
if "login" in current_url:
|
||||
print(f"{Fore.CYAN}{EMOJI['INFO']} Logging into GitHub...{Style.RESET_ALL}")
|
||||
|
||||
try:
|
||||
# Enter GitHub credentials
|
||||
username_field = WebDriverWait(self.browser, 10).until(
|
||||
EC.presence_of_element_located((By.ID, "login_field"))
|
||||
)
|
||||
username_field.send_keys(self.github_username)
|
||||
|
||||
password_field = self.browser.find_element(By.ID, "password")
|
||||
password_field.send_keys(self.github_password)
|
||||
|
||||
# Click sign in
|
||||
signin_button = self.browser.find_element(By.CSS_SELECTOR, "input[type='submit']")
|
||||
signin_button.click()
|
||||
time.sleep(5)
|
||||
except Exception as e:
|
||||
print(f"{Fore.RED}{EMOJI['ERROR']} Error during GitHub login: {str(e)}{Style.RESET_ALL}")
|
||||
return False
|
||||
|
||||
# Check if we're on the authorization page
|
||||
if "authorize" in self.browser.current_url:
|
||||
print(f"{Fore.CYAN}{EMOJI['INFO']} Authorizing Cursor app...{Style.RESET_ALL}")
|
||||
|
||||
try:
|
||||
# Look for authorization button
|
||||
auth_buttons = self.browser.find_elements(By.XPATH, "//button[contains(., 'Authorize') or contains(@class, 'btn-primary')]")
|
||||
|
||||
if auth_buttons:
|
||||
auth_buttons[0].click()
|
||||
print(f"{Fore.GREEN}{EMOJI['SUCCESS']} Cursor authorized with GitHub{Style.RESET_ALL}")
|
||||
time.sleep(5)
|
||||
else:
|
||||
print(f"{Fore.YELLOW}{EMOJI['WARNING']} No authorization button found, GitHub may be already authorized{Style.RESET_ALL}")
|
||||
except Exception as e:
|
||||
print(f"{Fore.RED}{EMOJI['ERROR']} Error during GitHub authorization: {str(e)}{Style.RESET_ALL}")
|
||||
|
||||
# Wait for Cursor dashboard to load
|
||||
timeout = 30
|
||||
start_time = time.time()
|
||||
while time.time() - start_time < timeout:
|
||||
if "cursor.sh" in self.browser.current_url and not "login" in self.browser.current_url:
|
||||
print(f"{Fore.GREEN}{EMOJI['SUCCESS']} Successfully logged into Cursor{Style.RESET_ALL}")
|
||||
break
|
||||
time.sleep(1)
|
||||
|
||||
if "login" in self.browser.current_url:
|
||||
print(f"{Fore.RED}{EMOJI['ERROR']} Failed to log into Cursor after {timeout} seconds{Style.RESET_ALL}")
|
||||
return False
|
||||
|
||||
# Wait for dashboard elements to load
|
||||
time.sleep(3)
|
||||
|
||||
print(f"{Fore.GREEN}{EMOJI['SUCCESS']} Cursor registered with GitHub successfully{Style.RESET_ALL}")
|
||||
|
||||
# Now reset the machine ID
|
||||
return self.reset_machine_id()
|
||||
|
||||
except Exception as e:
|
||||
print(f"{Fore.RED}{EMOJI['ERROR']} Error during Cursor registration: {str(e)}{Style.RESET_ALL}")
|
||||
return False
|
||||
|
||||
except Exception as e:
|
||||
print(f"{Fore.RED}{EMOJI['ERROR']} Failed to register with Cursor: {str(e)}{Style.RESET_ALL}")
|
||||
return False
|
||||
|
||||
def reset_machine_id(self):
|
||||
"""Reset the Cursor machine ID to bypass limitations"""
|
||||
try:
|
||||
print(f"{Fore.CYAN}{EMOJI['UPDATE']} Resetting Cursor machine ID...{Style.RESET_ALL}")
|
||||
|
||||
# Find Cursor app data location based on platform
|
||||
cursor_data_dir = None
|
||||
if platform.system() == "Windows":
|
||||
appdata = os.getenv('APPDATA')
|
||||
if appdata:
|
||||
cursor_data_dir = os.path.join(appdata, "cursor", "Local Storage", "leveldb")
|
||||
elif platform.system() == "Darwin": # macOS
|
||||
home = os.path.expanduser("~")
|
||||
cursor_data_dir = os.path.join(home, "Library", "Application Support", "cursor", "Local Storage", "leveldb")
|
||||
elif platform.system() == "Linux":
|
||||
home = os.path.expanduser("~")
|
||||
cursor_data_dir = os.path.join(home, ".config", "cursor", "Local Storage", "leveldb")
|
||||
|
||||
if not cursor_data_dir or not os.path.exists(cursor_data_dir):
|
||||
print(f"{Fore.YELLOW}{EMOJI['WARNING']} Cursor data directory not found at: {cursor_data_dir}{Style.RESET_ALL}")
|
||||
print(f"{Fore.YELLOW}{EMOJI['INFO']} You may need to reset the machine ID manually{Style.RESET_ALL}")
|
||||
|
||||
# Try to find the Cursor data directory
|
||||
if platform.system() == "Linux":
|
||||
possible_paths = [
|
||||
os.path.join(os.path.expanduser("~"), ".config", "cursor"),
|
||||
os.path.join(os.path.expanduser("~"), ".cursor")
|
||||
]
|
||||
for path in possible_paths:
|
||||
if os.path.exists(path):
|
||||
print(f"{Fore.GREEN}{EMOJI['SUCCESS']} Found Cursor directory at: {path}{Style.RESET_ALL}")
|
||||
# Look for Local Storage subfolder
|
||||
for root, dirs, files in os.walk(path):
|
||||
if "Local Storage" in dirs:
|
||||
cursor_data_dir = os.path.join(root, "Local Storage", "leveldb")
|
||||
print(f"{Fore.GREEN}{EMOJI['SUCCESS']} Found Cursor data directory at: {cursor_data_dir}{Style.RESET_ALL}")
|
||||
break
|
||||
break
|
||||
|
||||
if cursor_data_dir and os.path.exists(cursor_data_dir):
|
||||
# Generate a new UUID
|
||||
new_machine_id = str(uuid.uuid4())
|
||||
print(f"{Fore.CYAN}{EMOJI['KEY']} New machine ID: {new_machine_id}{Style.RESET_ALL}")
|
||||
|
||||
# Ask for permission to modify files
|
||||
print(f"{Fore.YELLOW}{EMOJI['WARNING']} This operation will modify Cursor app data files{Style.RESET_ALL}")
|
||||
print(f"{Fore.YELLOW}{EMOJI['INFO']} Do you want to continue? (yes/no){Style.RESET_ALL}")
|
||||
response = input().lower().strip()
|
||||
if response not in ['yes', 'y']:
|
||||
print(f"{Fore.YELLOW}{EMOJI['INFO']} Machine ID reset aborted{Style.RESET_ALL}")
|
||||
return False
|
||||
|
||||
# Backup the directory
|
||||
backup_dir = cursor_data_dir + "_backup_" + time.strftime("%Y%m%d%H%M%S")
|
||||
print(f"{Fore.CYAN}{EMOJI['INFO']} Creating backup of data directory to: {backup_dir}{Style.RESET_ALL}")
|
||||
try:
|
||||
shutil.copytree(cursor_data_dir, backup_dir)
|
||||
print(f"{Fore.GREEN}{EMOJI['SUCCESS']} Backup created successfully{Style.RESET_ALL}")
|
||||
except Exception as e:
|
||||
print(f"{Fore.YELLOW}{EMOJI['WARNING']} Failed to create backup: {str(e)}{Style.RESET_ALL}")
|
||||
print(f"{Fore.YELLOW}{EMOJI['INFO']} Continuing without backup...{Style.RESET_ALL}")
|
||||
|
||||
# Find and modify files containing the machine ID
|
||||
modified = False
|
||||
for filename in os.listdir(cursor_data_dir):
|
||||
if filename.endswith(".log") or filename.endswith(".ldb"):
|
||||
file_path = os.path.join(cursor_data_dir, filename)
|
||||
try:
|
||||
with open(file_path, "rb") as f:
|
||||
content = f.read()
|
||||
|
||||
# Look for patterns that might contain machine ID
|
||||
if b"machineId" in content:
|
||||
print(f"{Fore.CYAN}{EMOJI['INFO']} Found machineId reference in: {filename}{Style.RESET_ALL}")
|
||||
modified = True
|
||||
|
||||
# For safety, don't modify the binary files directly
|
||||
# Instead, instruct user to uninstall and reinstall Cursor
|
||||
print(f"{Fore.YELLOW}{EMOJI['WARNING']} Binary files found that may contain machine ID{Style.RESET_ALL}")
|
||||
print(f"{Fore.YELLOW}{EMOJI['INFO']} For best results, please:{Style.RESET_ALL}")
|
||||
print(f"{Fore.YELLOW}{EMOJI['INFO']} 1. Close Cursor if it's running{Style.RESET_ALL}")
|
||||
print(f"{Fore.YELLOW}{EMOJI['INFO']} 2. Uninstall Cursor completely{Style.RESET_ALL}")
|
||||
print(f"{Fore.YELLOW}{EMOJI['INFO']} 3. Reinstall Cursor{Style.RESET_ALL}")
|
||||
print(f"{Fore.YELLOW}{EMOJI['INFO']} 4. Login with your new GitHub account{Style.RESET_ALL}")
|
||||
break
|
||||
|
||||
except Exception as e:
|
||||
print(f"{Fore.YELLOW}{EMOJI['WARNING']} Error processing file {filename}: {str(e)}{Style.RESET_ALL}")
|
||||
|
||||
if not modified:
|
||||
print(f"{Fore.YELLOW}{EMOJI['WARNING']} No machine ID references found in data files{Style.RESET_ALL}")
|
||||
print(f"{Fore.YELLOW}{EMOJI['INFO']} You may need to reinstall Cursor for a complete reset{Style.RESET_ALL}")
|
||||
|
||||
# Save credentials before returning
|
||||
self.save_credentials()
|
||||
|
||||
print(f"{Fore.GREEN}{EMOJI['SUCCESS']} Machine ID reset process completed{Style.RESET_ALL}")
|
||||
return True
|
||||
else:
|
||||
print(f"{Fore.YELLOW}{EMOJI['WARNING']} Cursor data directory not found{Style.RESET_ALL}")
|
||||
print(f"{Fore.YELLOW}{EMOJI['INFO']} You may need to manually reset the machine ID by reinstalling Cursor{Style.RESET_ALL}")
|
||||
|
||||
# Still save credentials
|
||||
self.save_credentials()
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
print(f"{Fore.RED}{EMOJI['ERROR']} Failed to reset machine ID: {str(e)}{Style.RESET_ALL}")
|
||||
# Still save credentials even if machine ID reset fails
|
||||
self.save_credentials()
|
||||
return False
|
||||
|
||||
def save_credentials(self):
|
||||
"""Save the generated credentials to a file"""
|
||||
try:
|
||||
if not self.email_address or not self.github_username or not self.github_password:
|
||||
print(f"{Fore.RED}{EMOJI['ERROR']} No credentials to save{Style.RESET_ALL}")
|
||||
return False
|
||||
|
||||
output_file = "github_cursor_accounts.txt"
|
||||
timestamp = time.strftime("%Y-%m-%d %H:%M:%S")
|
||||
|
||||
credentials = {
|
||||
"timestamp": timestamp,
|
||||
"github_username": self.github_username,
|
||||
"github_password": self.github_password,
|
||||
"email": self.email_address
|
||||
}
|
||||
|
||||
credentials_json = json.dumps(credentials)
|
||||
|
||||
# Check if file exists and create if not
|
||||
file_exists = os.path.exists(output_file)
|
||||
|
||||
with open(output_file, "a") as f:
|
||||
if not file_exists:
|
||||
f.write("# GitHub + Cursor AI Accounts\n")
|
||||
f.write("# Format: JSON with timestamp, github_username, github_password, email\n\n")
|
||||
|
||||
f.write(credentials_json + "\n")
|
||||
|
||||
print(f"{Fore.GREEN}{EMOJI['SUCCESS']} Credentials saved to: {output_file}{Style.RESET_ALL}")
|
||||
|
||||
# Print a summary
|
||||
print(f"\n{Fore.GREEN}{EMOJI['SUCCESS']} Registration Summary:{Style.RESET_ALL}")
|
||||
print(f"{Fore.CYAN} • GitHub Username: {self.github_username}{Style.RESET_ALL}")
|
||||
print(f"{Fore.CYAN} • GitHub Password: {self.github_password}{Style.RESET_ALL}")
|
||||
print(f"{Fore.CYAN} • Email Address: {self.email_address}{Style.RESET_ALL}")
|
||||
print(f"{Fore.CYAN} • Saved to: {output_file}{Style.RESET_ALL}\n")
|
||||
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
print(f"{Fore.RED}{EMOJI['ERROR']} Failed to save credentials: {str(e)}{Style.RESET_ALL}")
|
||||
print(f"\n{Fore.YELLOW}{EMOJI['WARNING']} Make sure to copy these credentials manually:{Style.RESET_ALL}")
|
||||
print(f"{Fore.CYAN} • GitHub Username: {self.github_username}{Style.RESET_ALL}")
|
||||
print(f"{Fore.CYAN} • GitHub Password: {self.github_password}{Style.RESET_ALL}")
|
||||
print(f"{Fore.CYAN} • Email Address: {self.email_address}{Style.RESET_ALL}\n")
|
||||
return False
|
||||
|
||||
def cleanup(self):
|
||||
"""Clean up resources"""
|
||||
if self.browser:
|
||||
try:
|
||||
self.browser.quit()
|
||||
except:
|
||||
pass
|
||||
|
||||
def start_registration(self):
|
||||
"""Start the GitHub Cursor registration process"""
|
||||
try:
|
||||
# Step 1: Get temporary email
|
||||
if not self.get_temp_email():
|
||||
return False
|
||||
|
||||
# Step 2: Register GitHub account
|
||||
if not self.register_github():
|
||||
return False
|
||||
|
||||
# Step 3: Check and verify email
|
||||
if not self.check_email_verification():
|
||||
return False
|
||||
|
||||
# Step 4: Register Cursor with GitHub
|
||||
if not self.register_cursor():
|
||||
return False
|
||||
|
||||
# Step 5: Reset machine ID
|
||||
self.reset_machine_id()
|
||||
|
||||
return True
|
||||
finally:
|
||||
self.cleanup()
|
||||
|
||||
def display_features_and_warnings(translator=None):
|
||||
"""Display features and warnings before proceeding"""
|
||||
if translator:
|
||||
print(f"\n🚀 {translator.get('github_register.title')}")
|
||||
print("=====================================")
|
||||
print(f"{translator.get('github_register.features_header')}:")
|
||||
print(f" - {translator.get('github_register.feature1')}")
|
||||
print(f" - {translator.get('github_register.feature2')}")
|
||||
print(f" - {translator.get('github_register.feature3')}")
|
||||
print(f" - {translator.get('github_register.feature4')}")
|
||||
print(f" - {translator.get('github_register.feature5')}")
|
||||
print(f" - {translator.get('github_register.feature6')}")
|
||||
print(f"\n⚠️ {translator.get('github_register.warnings_header')}:")
|
||||
print(f" - {translator.get('github_register.warning1')}")
|
||||
print(f" - {translator.get('github_register.warning2')}")
|
||||
print(f" - {translator.get('github_register.warning3')}")
|
||||
print(f" - {translator.get('github_register.warning4')}")
|
||||
print("=====================================\n")
|
||||
else:
|
||||
print("\n🚀 GitHub + Cursor AI Registration Automation")
|
||||
print("=====================================")
|
||||
print("Features:")
|
||||
print(" - Creates a temporary email using YOPmail")
|
||||
print(" - Registers a new GitHub account with random credentials")
|
||||
print(" - Verifies the GitHub email automatically")
|
||||
print(" - Logs into Cursor AI using GitHub authentication")
|
||||
print(" - Resets the machine ID to bypass trial detection")
|
||||
print(" - Saves all credentials to a file")
|
||||
print("\n⚠️ Warnings:")
|
||||
print(" - This script automates account creation, which may violate GitHub/Cursor terms of service")
|
||||
print(" - Requires internet access and administrative privileges")
|
||||
print(" - CAPTCHA or additional verification may interrupt automation")
|
||||
print(" - Use responsibly and at your own risk")
|
||||
print("=====================================\n")
|
||||
|
||||
def get_user_confirmation(translator=None):
|
||||
"""Prompt the user for confirmation to proceed"""
|
||||
while True:
|
||||
if translator:
|
||||
response = input(f"{translator.get('github_register.confirm')} (yes/no): ").lower().strip()
|
||||
else:
|
||||
response = input("Do you want to proceed with GitHub + Cursor AI registration? (yes/no): ").lower().strip()
|
||||
|
||||
if response in ['yes', 'y']:
|
||||
return True
|
||||
elif response in ['no', 'n']:
|
||||
if translator:
|
||||
print(f"❌ {translator.get('github_register.cancelled')}")
|
||||
else:
|
||||
print("❌ Operation cancelled.")
|
||||
return False
|
||||
else:
|
||||
if translator:
|
||||
print(f"{translator.get('github_register.invalid_choice')}")
|
||||
else:
|
||||
print("Please enter 'yes' or 'no'.")
|
||||
|
||||
def main(translator=None):
|
||||
"""Main function to run the GitHub Cursor registration process"""
|
||||
logging.info(f"{Fore.CYAN} {translator.get('github_register.starting_automation')}{Style.RESET_ALL}")
|
||||
|
||||
# Display features and warnings
|
||||
display_features_and_warnings(translator)
|
||||
|
||||
# Get user confirmation
|
||||
if not get_user_confirmation(translator):
|
||||
return
|
||||
|
||||
# Start registration process
|
||||
registration = GitHubCursorRegistration(translator)
|
||||
success = registration.start_registration()
|
||||
|
||||
# Display final message
|
||||
if success:
|
||||
print(f"\n{Fore.GREEN}{EMOJI['DONE']} {translator.get('github_register.completed_successfully')}{Style.RESET_ALL}")
|
||||
print(f"{Fore.CYAN}{EMOJI['INFO']} {translator.get('github_register.github_username')}: {registration.github_username}{Style.RESET_ALL}")
|
||||
print(f"{Fore.CYAN}{EMOJI['INFO']} {translator.get('github_register.github_password')}: {registration.github_password}{Style.RESET_ALL}")
|
||||
print(f"{Fore.CYAN}{EMOJI['INFO']} {translator.get('github_register.email')}: {registration.email_address}{Style.RESET_ALL}")
|
||||
print(f"\n{Fore.CYAN}{EMOJI['INFO']} {translator.get('github_register.credentials_saved')}{Style.RESET_ALL}")
|
||||
else:
|
||||
print(f"\n{Fore.RED}{EMOJI['ERROR']} {translator.get('github_register.registration_encountered_issues')}{Style.RESET_ALL}")
|
||||
print(f"{Fore.YELLOW}{EMOJI['INFO']} {translator.get('github_register.check_browser_windows_for_manual_intervention_or_try_again_later')}{Style.RESET_ALL}")
|
||||
|
||||
# Wait for user acknowledgment
|
||||
if translator:
|
||||
input(f"\n{EMOJI['INFO']} {translator.get('register.press_enter')}...")
|
||||
else:
|
||||
input(f"\n{EMOJI['INFO']} Press Enter to continue...")
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
75
main.py
75
main.py
@ -284,22 +284,15 @@ def print_menu():
|
||||
menu_items = {
|
||||
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')}",
|
||||
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')}{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')}",
|
||||
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')}",
|
||||
8: f"{Fore.GREEN}8{Style.RESET_ALL}. {EMOJI['LANG']} {translator.get('menu.select_language')}",
|
||||
9: f"{Fore.GREEN}9{Style.RESET_ALL}. {EMOJI['UPDATE']} {translator.get('menu.disable_auto_update')}",
|
||||
10: f"{Fore.GREEN}10{Style.RESET_ALL}. {EMOJI['RESET']} {translator.get('menu.totally_reset')}",
|
||||
11: f"{Fore.GREEN}11{Style.RESET_ALL}. {EMOJI['CONTRIBUTE']} {translator.get('menu.contribute')}",
|
||||
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')}",
|
||||
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')}",
|
||||
16: f"{Fore.GREEN}16{Style.RESET_ALL}. {EMOJI['UPDATE']} {translator.get('menu.check_user_authorized', fallback='Check User Authorized')}",
|
||||
17: f"{Fore.GREEN}17{Style.RESET_ALL}. {EMOJI['UPDATE']} {translator.get('menu.bypass_token_limit', fallback='Bypass Token Limit')}"
|
||||
2: f"{Fore.GREEN}2{Style.RESET_ALL}. {EMOJI['ERROR']} {translator.get('menu.quit')}",
|
||||
3: f"{Fore.GREEN}3{Style.RESET_ALL}. {EMOJI['LANG']} {translator.get('menu.select_language')}",
|
||||
4: f"{Fore.GREEN}4{Style.RESET_ALL}. {EMOJI['UPDATE']} {translator.get('menu.disable_auto_update')}",
|
||||
5: f"{Fore.GREEN}5{Style.RESET_ALL}. {EMOJI['RESET']} {translator.get('menu.totally_reset')}",
|
||||
6: f"{Fore.GREEN}6{Style.RESET_ALL}. {EMOJI['CONTRIBUTE']} {translator.get('menu.contribute')}",
|
||||
7: f"{Fore.GREEN}7{Style.RESET_ALL}. {EMOJI['SETTINGS']} {translator.get('menu.config')}",
|
||||
8: f"{Fore.GREEN}8{Style.RESET_ALL}. {EMOJI['UPDATE']} {translator.get('menu.bypass_version_check', fallback='Bypass Cursor Version Check')}",
|
||||
9: f"{Fore.GREEN}9{Style.RESET_ALL}. {EMOJI['UPDATE']} {translator.get('menu.check_user_authorized', fallback='Check User Authorized')}",
|
||||
10: f"{Fore.GREEN}10{Style.RESET_ALL}. {EMOJI['UPDATE']} {translator.get('menu.bypass_token_limit', fallback='Bypass Token Limit')}"
|
||||
}
|
||||
|
||||
# Automatically calculate the number of menu items in the left and right columns
|
||||
@ -572,7 +565,7 @@ def main():
|
||||
|
||||
while True:
|
||||
try:
|
||||
choice_num = 17
|
||||
choice_num = 10
|
||||
choice = input(f"\n{EMOJI['ARROW']} {Fore.CYAN}{translator.get('menu.input_choice', choices=f'0-{choice_num}')}: {Style.RESET_ALL}")
|
||||
|
||||
match choice:
|
||||
@ -583,71 +576,41 @@ def main():
|
||||
case "1":
|
||||
import reset_machine_manual
|
||||
reset_machine_manual.run(translator)
|
||||
print_menu()
|
||||
print_menu()
|
||||
case "2":
|
||||
import cursor_register
|
||||
cursor_register.main(translator)
|
||||
print_menu()
|
||||
case "3":
|
||||
import cursor_register_google
|
||||
cursor_register_google.main(translator)
|
||||
print_menu()
|
||||
case "4":
|
||||
import cursor_register_github
|
||||
cursor_register_github.main(translator)
|
||||
print_menu()
|
||||
case "5":
|
||||
import cursor_register_manual
|
||||
cursor_register_manual.main(translator)
|
||||
print_menu()
|
||||
case "6":
|
||||
import github_cursor_register
|
||||
print(f"{Fore.YELLOW}{EMOJI['INFO']} {translator.get('menu.coming_soon')}{Style.RESET_ALL}")
|
||||
# github_cursor_register.main(translator)
|
||||
print_menu()
|
||||
case "7":
|
||||
import quit_cursor
|
||||
quit_cursor.quit_cursor(translator)
|
||||
print_menu()
|
||||
case "8":
|
||||
case "3":
|
||||
if select_language():
|
||||
print_menu()
|
||||
continue
|
||||
case "9":
|
||||
case "4":
|
||||
import disable_auto_update
|
||||
disable_auto_update.run(translator)
|
||||
print_menu()
|
||||
case "10":
|
||||
case "5":
|
||||
import totally_reset_cursor
|
||||
totally_reset_cursor.run(translator)
|
||||
# print(f"{Fore.YELLOW}{EMOJI['INFO']} {translator.get('menu.fixed_soon')}{Style.RESET_ALL}")
|
||||
print_menu()
|
||||
case "11":
|
||||
case "6":
|
||||
import logo
|
||||
print(logo.CURSOR_CONTRIBUTORS)
|
||||
print_menu()
|
||||
case "12":
|
||||
case "7":
|
||||
from config import print_config
|
||||
print_config(get_config(), translator)
|
||||
print_menu()
|
||||
case "13":
|
||||
from oauth_auth import OAuthHandler
|
||||
oauth = OAuthHandler(translator)
|
||||
oauth._select_profile()
|
||||
print_menu()
|
||||
case "14":
|
||||
import delete_cursor_google
|
||||
delete_cursor_google.main(translator)
|
||||
print_menu()
|
||||
case "15":
|
||||
case "8":
|
||||
import bypass_version
|
||||
bypass_version.main(translator)
|
||||
print_menu()
|
||||
case "16":
|
||||
case "9":
|
||||
import check_user_authorized
|
||||
check_user_authorized.main(translator)
|
||||
print_menu()
|
||||
case "17":
|
||||
case "10":
|
||||
import bypass_token_limit
|
||||
bypass_token_limit.run(translator)
|
||||
print_menu()
|
||||
|
692
new_signup.py
692
new_signup.py
@ -1,692 +0,0 @@
|
||||
from DrissionPage import ChromiumOptions, ChromiumPage
|
||||
import time
|
||||
import os
|
||||
import signal
|
||||
import random
|
||||
from colorama import Fore, Style
|
||||
import configparser
|
||||
from pathlib import Path
|
||||
import sys
|
||||
from config import get_config
|
||||
from utils import get_default_browser_path as utils_get_default_browser_path
|
||||
|
||||
# Add global variable at the beginning of the file
|
||||
_translator = None
|
||||
|
||||
# Add global variable to track our Chrome processes
|
||||
_chrome_process_ids = []
|
||||
|
||||
def cleanup_chrome_processes(translator=None):
|
||||
"""Clean only Chrome processes launched by this script"""
|
||||
global _chrome_process_ids
|
||||
|
||||
if not _chrome_process_ids:
|
||||
print("\nNo Chrome processes to clean...")
|
||||
return
|
||||
|
||||
print("\nCleaning Chrome processes launched by this script...")
|
||||
try:
|
||||
if os.name == 'nt':
|
||||
for pid in _chrome_process_ids:
|
||||
try:
|
||||
os.system(f'taskkill /F /PID {pid} /T 2>nul')
|
||||
except:
|
||||
pass
|
||||
else:
|
||||
for pid in _chrome_process_ids:
|
||||
try:
|
||||
os.kill(pid, signal.SIGTERM)
|
||||
except:
|
||||
pass
|
||||
_chrome_process_ids = [] # Reset the list after cleanup
|
||||
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):
|
||||
"""Handle Ctrl+C signal"""
|
||||
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, config, translator=None):
|
||||
"""Visit URL"""
|
||||
if translator:
|
||||
print(f"{Fore.CYAN}🚀 {translator.get('register.visiting_url')}: {url}{Style.RESET_ALL}")
|
||||
|
||||
# First visit blank page
|
||||
page.get('about:blank')
|
||||
time.sleep(get_random_wait_time(config, 'page_load_wait'))
|
||||
|
||||
# Visit target page
|
||||
page.get(url)
|
||||
time.sleep(get_random_wait_time(config, 'page_load_wait'))
|
||||
|
||||
def fill_signup_form(page, first_name, last_name, email, config, translator=None):
|
||||
"""Fill signup form"""
|
||||
try:
|
||||
if translator:
|
||||
print(f"{Fore.CYAN}📧 {translator.get('register.filling_form')}{Style.RESET_ALL}")
|
||||
else:
|
||||
print("\n正在填写注册表单...")
|
||||
|
||||
# Fill first name
|
||||
first_name_input = page.ele("@name=first_name")
|
||||
if first_name_input:
|
||||
first_name_input.input(first_name)
|
||||
time.sleep(get_random_wait_time(config, 'input_wait'))
|
||||
|
||||
# Fill last name
|
||||
last_name_input = page.ele("@name=last_name")
|
||||
if last_name_input:
|
||||
last_name_input.input(last_name)
|
||||
time.sleep(get_random_wait_time(config, 'input_wait'))
|
||||
|
||||
# Fill email
|
||||
email_input = page.ele("@name=email")
|
||||
if email_input:
|
||||
email_input.input(email)
|
||||
time.sleep(get_random_wait_time(config, 'input_wait'))
|
||||
|
||||
# Click submit button
|
||||
submit_button = page.ele("@type=submit")
|
||||
if submit_button:
|
||||
submit_button.click()
|
||||
time.sleep(get_random_wait_time(config, 'submit_wait'))
|
||||
|
||||
if translator:
|
||||
print(f"{Fore.GREEN}✅ {translator.get('register.form_success')}{Style.RESET_ALL}")
|
||||
else:
|
||||
print("Form filled successfully")
|
||||
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"Error filling form: {e}")
|
||||
return False
|
||||
|
||||
def get_user_documents_path():
|
||||
"""Get user Documents folder path"""
|
||||
if sys.platform == "win32":
|
||||
return os.path.join(os.path.expanduser("~"), "Documents")
|
||||
elif sys.platform == "darwin":
|
||||
return os.path.join(os.path.expanduser("~"), "Documents")
|
||||
else: # Linux
|
||||
# Get actual user's home directory
|
||||
sudo_user = os.environ.get('SUDO_USER')
|
||||
if sudo_user:
|
||||
return os.path.join("/home", sudo_user, "Documents")
|
||||
return os.path.join(os.path.expanduser("~"), "Documents")
|
||||
|
||||
def get_random_wait_time(config, timing_type='page_load_wait'):
|
||||
"""
|
||||
Get random wait time from config
|
||||
Args:
|
||||
config: ConfigParser object
|
||||
timing_type: Type of timing to get (page_load_wait, input_wait, submit_wait)
|
||||
Returns:
|
||||
float: Random wait time or fixed time
|
||||
"""
|
||||
try:
|
||||
if not config.has_section('Timing'):
|
||||
return random.uniform(0.1, 0.8) # Default value
|
||||
|
||||
if timing_type == 'random':
|
||||
min_time = float(config.get('Timing', 'min_random_time', fallback='0.1'))
|
||||
max_time = float(config.get('Timing', 'max_random_time', fallback='0.8'))
|
||||
return random.uniform(min_time, max_time)
|
||||
|
||||
time_value = config.get('Timing', timing_type, fallback='0.1-0.8')
|
||||
|
||||
# Check if it's a fixed time value
|
||||
if '-' not in time_value and ',' not in time_value:
|
||||
return float(time_value) # Return fixed time
|
||||
|
||||
# Process range time
|
||||
min_time, max_time = map(float, time_value.split('-' if '-' in time_value else ','))
|
||||
return random.uniform(min_time, max_time)
|
||||
except:
|
||||
return random.uniform(0.1, 0.8) # Return default value when error
|
||||
|
||||
def setup_driver(translator=None):
|
||||
"""Setup browser driver"""
|
||||
global _chrome_process_ids
|
||||
|
||||
try:
|
||||
# Get config
|
||||
config = get_config(translator)
|
||||
|
||||
# Get browser type and path
|
||||
browser_type = config.get('Browser', 'default_browser', fallback='chrome')
|
||||
browser_path = config.get('Browser', f'{browser_type}_path', fallback=utils_get_default_browser_path(browser_type))
|
||||
|
||||
if not browser_path or not os.path.exists(browser_path):
|
||||
if translator:
|
||||
print(f"{Fore.YELLOW}⚠️ {browser_type} {translator.get('register.browser_path_invalid')}{Style.RESET_ALL}")
|
||||
browser_path = utils_get_default_browser_path(browser_type)
|
||||
|
||||
# For backward compatibility, also check Chrome path
|
||||
if browser_type == 'chrome':
|
||||
chrome_path = config.get('Chrome', 'chromepath', fallback=None)
|
||||
if chrome_path and os.path.exists(chrome_path):
|
||||
browser_path = chrome_path
|
||||
|
||||
# Set browser options
|
||||
co = ChromiumOptions()
|
||||
|
||||
# Set browser path
|
||||
co.set_browser_path(browser_path)
|
||||
|
||||
# Use incognito mode
|
||||
co.set_argument("--incognito")
|
||||
|
||||
if sys.platform == "linux":
|
||||
# Set Linux specific options
|
||||
co.set_argument("--no-sandbox")
|
||||
|
||||
# Set random port
|
||||
co.auto_port()
|
||||
|
||||
# Use headless mode (must be set to False, simulate human operation)
|
||||
co.headless(False)
|
||||
|
||||
# Log browser info
|
||||
if translator:
|
||||
print(f"{Fore.CYAN}🌐 {translator.get('register.using_browser')}: {browser_type} {browser_path}{Style.RESET_ALL}")
|
||||
|
||||
try:
|
||||
# Load extension
|
||||
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"Error loading extension: {e}")
|
||||
|
||||
if translator:
|
||||
print(f"{Fore.CYAN}🚀 {translator.get('register.starting_browser')}{Style.RESET_ALL}")
|
||||
else:
|
||||
print("Starting browser...")
|
||||
|
||||
# Record Chrome processes before launching
|
||||
before_pids = []
|
||||
try:
|
||||
import psutil
|
||||
browser_process_names = {
|
||||
'chrome': ['chrome', 'chromium'],
|
||||
'edge': ['msedge', 'edge'],
|
||||
'firefox': ['firefox'],
|
||||
'brave': ['brave', 'brave-browser']
|
||||
}
|
||||
process_names = browser_process_names.get(browser_type, ['chrome'])
|
||||
before_pids = [p.pid for p in psutil.process_iter() if any(name in p.name().lower() for name in process_names)]
|
||||
except:
|
||||
pass
|
||||
|
||||
# Launch browser
|
||||
page = ChromiumPage(co)
|
||||
|
||||
# Wait a moment for browser to fully launch
|
||||
time.sleep(1)
|
||||
|
||||
# Record browser processes after launching and find new ones
|
||||
try:
|
||||
import psutil
|
||||
process_names = browser_process_names.get(browser_type, ['chrome'])
|
||||
after_pids = [p.pid for p in psutil.process_iter() if any(name in p.name().lower() for name in process_names)]
|
||||
# Find new browser processes
|
||||
new_pids = [pid for pid in after_pids if pid not in before_pids]
|
||||
_chrome_process_ids.extend(new_pids)
|
||||
|
||||
if _chrome_process_ids:
|
||||
print(f"{translator.get('register.tracking_processes', count=len(_chrome_process_ids), browser=browser_type)}")
|
||||
else:
|
||||
print(f"{Fore.YELLOW}Warning: {translator.get('register.no_new_processes_detected', browser=browser_type)}{Style.RESET_ALL}")
|
||||
except Exception as e:
|
||||
print(f"{translator.get('register.could_not_track_processes', browser=browser_type, error=str(e))}")
|
||||
|
||||
return config, page
|
||||
|
||||
except Exception as e:
|
||||
if translator:
|
||||
print(f"{Fore.RED}❌ {translator.get('register.browser_setup_error', error=str(e))}{Style.RESET_ALL}")
|
||||
else:
|
||||
print(f"Error setting up browser: {e}")
|
||||
raise
|
||||
|
||||
def handle_turnstile(page, config, translator=None):
|
||||
"""Handle Turnstile verification"""
|
||||
try:
|
||||
if translator:
|
||||
print(f"{Fore.CYAN}🔄 {translator.get('register.handling_turnstile')}{Style.RESET_ALL}")
|
||||
else:
|
||||
print("\nHandling Turnstile verification...")
|
||||
|
||||
# from config
|
||||
turnstile_time = float(config.get('Turnstile', 'handle_turnstile_time', fallback='2'))
|
||||
random_time_str = config.get('Turnstile', 'handle_turnstile_random_time', fallback='1-3')
|
||||
|
||||
# Parse random time range
|
||||
try:
|
||||
min_time, max_time = map(float, random_time_str.split('-'))
|
||||
except:
|
||||
min_time, max_time = 1, 3 # Default value
|
||||
|
||||
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"Attempt {retry_count} of verification...")
|
||||
|
||||
try:
|
||||
# Try to reset turnstile
|
||||
page.run_js("try { turnstile.reset() } catch(e) { }")
|
||||
time.sleep(turnstile_time) # from config
|
||||
|
||||
# Locate verification box element
|
||||
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("Detected verification box...")
|
||||
|
||||
# from config
|
||||
time.sleep(random.uniform(min_time, max_time))
|
||||
challenge_check.click()
|
||||
time.sleep(turnstile_time) # from config
|
||||
|
||||
# check verification result
|
||||
if check_verification_success(page, translator):
|
||||
if translator:
|
||||
print(f"{Fore.GREEN}✅ {translator.get('register.verification_success')}{Style.RESET_ALL}")
|
||||
else:
|
||||
print("Verification successful!")
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
if translator:
|
||||
print(f"{Fore.RED}❌ {translator.get('register.verification_failed')}{Style.RESET_ALL}")
|
||||
else:
|
||||
print(f"Verification attempt failed: {e}")
|
||||
|
||||
# Check if verification has been successful
|
||||
if check_verification_success(page, translator):
|
||||
if translator:
|
||||
print(f"{Fore.GREEN}✅ {translator.get('register.verification_success')}{Style.RESET_ALL}")
|
||||
else:
|
||||
print("Verification successful!")
|
||||
return True
|
||||
|
||||
time.sleep(random.uniform(min_time, max_time))
|
||||
|
||||
if translator:
|
||||
print(f"{Fore.RED}❌ {translator.get('register.verification_failed')}{Style.RESET_ALL}")
|
||||
else:
|
||||
print("Exceeded maximum retry attempts")
|
||||
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"Error in verification process: {e}")
|
||||
return False
|
||||
|
||||
def check_verification_success(page, translator=None):
|
||||
"""Check if verification is successful"""
|
||||
try:
|
||||
# Check if there is a subsequent form element, indicating verification has passed
|
||||
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
|
||||
|
||||
# Check if there is an error message
|
||||
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):
|
||||
"""Generate random password"""
|
||||
chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!@#$%^&*"
|
||||
return ''.join(random.choices(chars, k=length))
|
||||
|
||||
def fill_password(page, password: str, config, translator=None):
|
||||
"""
|
||||
Fill password form
|
||||
"""
|
||||
try:
|
||||
print(f"{Fore.CYAN}🔑 {translator.get('register.setting_password') if translator else 'Setting password'}{Style.RESET_ALL}")
|
||||
|
||||
# Fill password
|
||||
password_input = page.ele("@name=password")
|
||||
print(f"{Fore.CYAN}🔑 {translator.get('register.setting_on_password')}: {password}{Style.RESET_ALL}")
|
||||
if password_input:
|
||||
password_input.input(password)
|
||||
|
||||
# Click submit button
|
||||
submit_button = page.ele("@type=submit")
|
||||
if submit_button:
|
||||
submit_button.click()
|
||||
time.sleep(get_random_wait_time(config, 'submit_wait'))
|
||||
|
||||
print(f"{Fore.GREEN}✅ {translator.get('register.password_submitted') if translator else 'Password submitted'}{Style.RESET_ALL}")
|
||||
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
print(f"{Fore.RED}❌ {translator.get('register.password_error', error=str(e)) if translator else f'Error setting password: {str(e)}'}{Style.RESET_ALL}")
|
||||
|
||||
return False
|
||||
|
||||
def handle_verification_code(browser_tab, email_tab, controller, config, translator=None):
|
||||
"""Handle verification code"""
|
||||
try:
|
||||
if translator:
|
||||
print(f"\n{Fore.CYAN}🔄 {translator.get('register.waiting_for_verification_code')}{Style.RESET_ALL}")
|
||||
|
||||
# Check if using manual input verification code
|
||||
if hasattr(controller, 'get_verification_code') and email_tab is None: # Manual mode
|
||||
verification_code = controller.get_verification_code()
|
||||
if verification_code:
|
||||
# Fill verification code in registration page
|
||||
for i, digit in enumerate(verification_code):
|
||||
browser_tab.ele(f"@data-index={i}").input(digit)
|
||||
time.sleep(get_random_wait_time(config, 'verification_code_input'))
|
||||
|
||||
print(f"{translator.get('register.verification_success')}")
|
||||
time.sleep(get_random_wait_time(config, 'verification_success_wait'))
|
||||
|
||||
# Handle last Turnstile verification
|
||||
if handle_turnstile(browser_tab, config, translator):
|
||||
if translator:
|
||||
print(f"{Fore.GREEN}✅ {translator.get('register.verification_success')}{Style.RESET_ALL}")
|
||||
time.sleep(get_random_wait_time(config, 'verification_retry_wait'))
|
||||
|
||||
# Visit settings page
|
||||
print(f"{Fore.CYAN}🔑 {translator.get('register.visiting_url')}: https://www.cursor.com/settings{Style.RESET_ALL}")
|
||||
browser_tab.get("https://www.cursor.com/settings")
|
||||
time.sleep(get_random_wait_time(config, 'settings_page_load_wait'))
|
||||
return True, browser_tab
|
||||
|
||||
return False, None
|
||||
|
||||
# Automatic verification code logic
|
||||
elif email_tab:
|
||||
print(f"{Fore.CYAN}🔄 {translator.get('register.waiting_for_verification_code')}{Style.RESET_ALL}")
|
||||
time.sleep(get_random_wait_time(config, 'email_check_initial_wait'))
|
||||
|
||||
# Use existing email_tab to refresh email
|
||||
email_tab.refresh_inbox()
|
||||
time.sleep(get_random_wait_time(config, 'email_refresh_wait'))
|
||||
|
||||
# Check if there is a verification code email
|
||||
if email_tab.check_for_cursor_email():
|
||||
verification_code = email_tab.get_verification_code()
|
||||
if verification_code:
|
||||
# Fill verification code in registration page
|
||||
for i, digit in enumerate(verification_code):
|
||||
browser_tab.ele(f"@data-index={i}").input(digit)
|
||||
time.sleep(get_random_wait_time(config, 'verification_code_input'))
|
||||
|
||||
if translator:
|
||||
print(f"{Fore.GREEN}✅ {translator.get('register.verification_success')}{Style.RESET_ALL}")
|
||||
time.sleep(get_random_wait_time(config, 'verification_success_wait'))
|
||||
|
||||
# Handle last Turnstile verification
|
||||
if handle_turnstile(browser_tab, config, translator):
|
||||
if translator:
|
||||
print(f"{Fore.GREEN}✅ {translator.get('register.verification_success')}{Style.RESET_ALL}")
|
||||
time.sleep(get_random_wait_time(config, 'verification_retry_wait'))
|
||||
|
||||
# Visit settings page
|
||||
if translator:
|
||||
print(f"{Fore.CYAN}🔑 {translator.get('register.visiting_url')}: https://www.cursor.com/settings{Style.RESET_ALL}")
|
||||
browser_tab.get("https://www.cursor.com/settings")
|
||||
time.sleep(get_random_wait_time(config, 'settings_page_load_wait'))
|
||||
return True, browser_tab
|
||||
|
||||
else:
|
||||
if translator:
|
||||
print(f"{Fore.RED}❌ {translator.get('register.verification_failed')}{Style.RESET_ALL}")
|
||||
else:
|
||||
print("最后一次验证失败")
|
||||
return False, None
|
||||
|
||||
# Get verification code, set timeout
|
||||
verification_code = None
|
||||
max_attempts = 20
|
||||
retry_interval = get_random_wait_time(config, 'retry_interval') # Use get_random_wait_time
|
||||
start_time = time.time()
|
||||
timeout = float(config.get('Timing', 'max_timeout', fallback='160')) # This can be kept unchanged because it is a fixed value
|
||||
|
||||
if translator:
|
||||
print(f"{Fore.CYAN}{translator.get('register.start_getting_verification_code')}{Style.RESET_ALL}")
|
||||
|
||||
for attempt in range(max_attempts):
|
||||
# Check if timeout
|
||||
if time.time() - start_time > timeout:
|
||||
if translator:
|
||||
print(f"{Fore.RED}❌ {translator.get('register.verification_timeout')}{Style.RESET_ALL}")
|
||||
break
|
||||
|
||||
verification_code = controller.get_verification_code()
|
||||
if verification_code:
|
||||
if translator:
|
||||
print(f"{Fore.GREEN}✅ {translator.get('register.verification_success')}{Style.RESET_ALL}")
|
||||
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}")
|
||||
|
||||
# Refresh email
|
||||
email_tab.refresh_inbox()
|
||||
time.sleep(retry_interval) # Use get_random_wait_time
|
||||
|
||||
if verification_code:
|
||||
# Fill verification code in registration page
|
||||
for i, digit in enumerate(verification_code):
|
||||
browser_tab.ele(f"@data-index={i}").input(digit)
|
||||
time.sleep(get_random_wait_time(config, 'verification_code_input'))
|
||||
|
||||
if translator:
|
||||
print(f"{Fore.GREEN}✅ {translator.get('register.verification_success')}{Style.RESET_ALL}")
|
||||
time.sleep(get_random_wait_time(config, 'verification_success_wait'))
|
||||
|
||||
# Handle last Turnstile verification
|
||||
if handle_turnstile(browser_tab, config, translator):
|
||||
if translator:
|
||||
print(f"{Fore.GREEN}✅ {translator.get('register.verification_success')}{Style.RESET_ALL}")
|
||||
time.sleep(get_random_wait_time(config, 'verification_retry_wait'))
|
||||
|
||||
# Visit settings page
|
||||
if translator:
|
||||
print(f"{Fore.CYAN}{translator.get('register.visiting_url')}: https://www.cursor.com/settings{Style.RESET_ALL}")
|
||||
browser_tab.get("https://www.cursor.com/settings")
|
||||
time.sleep(get_random_wait_time(config, 'settings_page_load_wait'))
|
||||
|
||||
# Return success directly, let cursor_register.py handle account information acquisition
|
||||
return True, browser_tab
|
||||
|
||||
else:
|
||||
if translator:
|
||||
print(f"{Fore.RED}❌ {translator.get('register.verification_failed')}{Style.RESET_ALL}")
|
||||
return False, None
|
||||
|
||||
return False, None
|
||||
|
||||
except Exception as e:
|
||||
if translator:
|
||||
print(f"{Fore.RED}❌ {translator.get('register.verification_error', error=str(e))}{Style.RESET_ALL}")
|
||||
return False, None
|
||||
|
||||
def handle_sign_in(browser_tab, email, password, translator=None):
|
||||
"""Handle login process"""
|
||||
try:
|
||||
# Check if on login page
|
||||
sign_in_header = browser_tab.ele('xpath://h1[contains(text(), "Sign in")]')
|
||||
if not sign_in_header:
|
||||
return True # If not on login page, it means login is successful
|
||||
|
||||
print(f"{Fore.CYAN}检测到登录页面,开始登录...{Style.RESET_ALL}")
|
||||
|
||||
# Fill email
|
||||
email_input = browser_tab.ele('@name=email')
|
||||
if email_input:
|
||||
email_input.input(email)
|
||||
time.sleep(1)
|
||||
|
||||
# Click Continue
|
||||
continue_button = browser_tab.ele('xpath://button[contains(@class, "BrandedButton") and text()="Continue"]')
|
||||
if continue_button:
|
||||
continue_button.click()
|
||||
time.sleep(2)
|
||||
|
||||
# Handle Turnstile verification
|
||||
if handle_turnstile(browser_tab, translator):
|
||||
# Fill password
|
||||
password_input = browser_tab.ele('@name=password')
|
||||
if password_input:
|
||||
password_input.input(password)
|
||||
time.sleep(1)
|
||||
|
||||
# Click 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)
|
||||
|
||||
# Handle last Turnstile verification
|
||||
if handle_turnstile(browser_tab, translator):
|
||||
print(f"{Fore.GREEN}Login successful!{Style.RESET_ALL}")
|
||||
time.sleep(3)
|
||||
return True
|
||||
|
||||
print(f"{Fore.RED}Login failed{Style.RESET_ALL}")
|
||||
return False
|
||||
|
||||
except Exception as e:
|
||||
print(f"{Fore.RED}Login process error: {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):
|
||||
"""Main function, can receive account information, email tab, and translator"""
|
||||
global _translator
|
||||
global _chrome_process_ids
|
||||
_translator = translator # Save to global variable
|
||||
_chrome_process_ids = [] # Reset the process IDs list
|
||||
|
||||
signal.signal(signal.SIGINT, signal_handler)
|
||||
signal.signal(signal.SIGTERM, signal_handler)
|
||||
|
||||
page = None
|
||||
success = False
|
||||
try:
|
||||
config, page = setup_driver(translator)
|
||||
if translator:
|
||||
print(f"{Fore.CYAN}🚀 {translator.get('register.browser_started')}{Style.RESET_ALL}")
|
||||
|
||||
# Visit registration page
|
||||
url = "https://authenticator.cursor.sh/sign-up"
|
||||
|
||||
# Visit page
|
||||
simulate_human_input(page, url, config, translator)
|
||||
if translator:
|
||||
print(f"{Fore.CYAN}🔄 {translator.get('register.waiting_for_page_load')}{Style.RESET_ALL}")
|
||||
time.sleep(get_random_wait_time(config, 'page_load_wait'))
|
||||
|
||||
# If account information is not provided, generate random information
|
||||
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()
|
||||
|
||||
# Save account information
|
||||
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")
|
||||
|
||||
# Fill form
|
||||
if fill_signup_form(page, first_name, last_name, email, config, translator):
|
||||
if translator:
|
||||
print(f"\n{Fore.GREEN}✅ {translator.get('register.form_submitted')}{Style.RESET_ALL}")
|
||||
|
||||
# Handle first Turnstile verification
|
||||
if handle_turnstile(page, config, translator):
|
||||
if translator:
|
||||
print(f"\n{Fore.GREEN}✅ {translator.get('register.first_verification_passed')}{Style.RESET_ALL}")
|
||||
|
||||
# Fill password
|
||||
if fill_password(page, password, config, translator):
|
||||
if translator:
|
||||
print(f"\n{Fore.CYAN}🔄 {translator.get('register.waiting_for_second_verification')}{Style.RESET_ALL}")
|
||||
|
||||
# Handle second Turnstile verification
|
||||
if handle_turnstile(page, config, translator):
|
||||
if translator:
|
||||
print(f"\n{Fore.CYAN}🔄 {translator.get('register.waiting_for_verification_code')}{Style.RESET_ALL}")
|
||||
if handle_verification_code(page, email_tab, controller, config, translator):
|
||||
success = True
|
||||
return True, page
|
||||
else:
|
||||
print(f"\n{Fore.RED}❌ {translator.get('register.verification_code_processing_failed') if translator else 'Verification code processing failed'}{Style.RESET_ALL}")
|
||||
else:
|
||||
print(f"\n{Fore.RED}❌ {translator.get('register.second_verification_failed') if translator else 'Second verification failed'}{Style.RESET_ALL}")
|
||||
else:
|
||||
print(f"\n{Fore.RED}❌ {translator.get('register.second_verification_failed') if translator else 'Second verification failed'}{Style.RESET_ALL}")
|
||||
else:
|
||||
print(f"\n{Fore.RED}❌ {translator.get('register.first_verification_failed') if translator else 'First verification failed'}{Style.RESET_ALL}")
|
||||
|
||||
return False, None
|
||||
|
||||
except Exception as e:
|
||||
print(f"发生错误: {e}")
|
||||
return False, None
|
||||
finally:
|
||||
if page and not success: # Only clean up when failed
|
||||
try:
|
||||
page.quit()
|
||||
except:
|
||||
pass
|
||||
cleanup_chrome_processes(translator)
|
||||
|
||||
if __name__ == "__main__":
|
||||
main() # Run without parameters, use randomly generated information
|
393
new_tempemail.py
393
new_tempemail.py
@ -1,393 +0,0 @@
|
||||
from DrissionPage import ChromiumPage, ChromiumOptions
|
||||
import time
|
||||
import os
|
||||
import sys
|
||||
from colorama import Fore, Style, init
|
||||
import requests
|
||||
import random
|
||||
import string
|
||||
from config import get_config
|
||||
from utils import get_random_wait_time, get_default_browser_path as utils_get_default_browser_path
|
||||
|
||||
# Initialize colorama
|
||||
init()
|
||||
|
||||
class NewTempEmail:
|
||||
def __init__(self, translator=None):
|
||||
self.translator = translator
|
||||
self.page = None
|
||||
self.setup_browser()
|
||||
|
||||
def get_blocked_domains(self):
|
||||
"""Get blocked domains list"""
|
||||
try:
|
||||
block_url = "https://raw.githubusercontent.com/yeongpin/cursor-free-vip/main/block_domain.txt"
|
||||
response = requests.get(block_url, timeout=5)
|
||||
if response.status_code == 200:
|
||||
# Split text and remove empty lines
|
||||
domains = [line.strip() for line in response.text.split('\n') if line.strip()]
|
||||
if self.translator:
|
||||
print(f"{Fore.CYAN}ℹ️ {self.translator.get('email.blocked_domains_loaded', count=len(domains))}{Style.RESET_ALL}")
|
||||
else:
|
||||
print(f"{Fore.CYAN}ℹ️ 已加载 {len(domains)} 个被屏蔽的域名{Style.RESET_ALL}")
|
||||
return domains
|
||||
return self._load_local_blocked_domains()
|
||||
except Exception as e:
|
||||
if self.translator:
|
||||
print(f"{Fore.YELLOW}⚠️ {self.translator.get('email.blocked_domains_error', error=str(e))}{Style.RESET_ALL}")
|
||||
else:
|
||||
print(f"{Fore.YELLOW}⚠️ 获取被屏蔽域名列表失败: {str(e)}{Style.RESET_ALL}")
|
||||
return self._load_local_blocked_domains()
|
||||
|
||||
def _load_local_blocked_domains(self):
|
||||
"""Load blocked domains from local file as fallback"""
|
||||
try:
|
||||
local_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), "block_domain.txt")
|
||||
if os.path.exists(local_path):
|
||||
with open(local_path, 'r', encoding='utf-8') as f:
|
||||
domains = [line.strip() for line in f.readlines() if line.strip()]
|
||||
if self.translator:
|
||||
print(f"{Fore.CYAN}ℹ️ {self.translator.get('email.local_blocked_domains_loaded', count=len(domains))}{Style.RESET_ALL}")
|
||||
else:
|
||||
print(f"{Fore.CYAN}ℹ️ 已从本地加载 {len(domains)} 个被屏蔽的域名{Style.RESET_ALL}")
|
||||
return domains
|
||||
else:
|
||||
if self.translator:
|
||||
print(f"{Fore.YELLOW}⚠️ {self.translator.get('email.local_blocked_domains_not_found')}{Style.RESET_ALL}")
|
||||
else:
|
||||
print(f"{Fore.YELLOW}⚠️ 本地被屏蔽域名文件不存在{Style.RESET_ALL}")
|
||||
return []
|
||||
except Exception as e:
|
||||
if self.translator:
|
||||
print(f"{Fore.YELLOW}⚠️ {self.translator.get('email.local_blocked_domains_error', error=str(e))}{Style.RESET_ALL}")
|
||||
else:
|
||||
print(f"{Fore.YELLOW}⚠️ 读取本地被屏蔽域名文件失败: {str(e)}{Style.RESET_ALL}")
|
||||
return []
|
||||
|
||||
def exclude_blocked_domains(self, domains):
|
||||
"""Exclude blocked domains"""
|
||||
if not self.blocked_domains:
|
||||
return domains
|
||||
|
||||
filtered_domains = []
|
||||
for domain in domains:
|
||||
if domain['domain'] not in self.blocked_domains:
|
||||
filtered_domains.append(domain)
|
||||
|
||||
excluded_count = len(domains) - len(filtered_domains)
|
||||
if excluded_count > 0:
|
||||
if self.translator:
|
||||
print(f"{Fore.YELLOW}⚠️ {self.translator.get('email.domains_excluded', domains=excluded_count)}{Style.RESET_ALL}")
|
||||
else:
|
||||
print(f"{Fore.YELLOW}⚠️ 已排除 {excluded_count} 个被屏蔽的域名{Style.RESET_ALL}")
|
||||
|
||||
return filtered_domains
|
||||
|
||||
|
||||
def get_extension_block(self):
|
||||
"""获取插件路径"""
|
||||
root_dir = os.getcwd()
|
||||
extension_path = os.path.join(root_dir, "PBlock")
|
||||
|
||||
if hasattr(sys, "_MEIPASS"):
|
||||
extension_path = os.path.join(sys._MEIPASS, "PBlock")
|
||||
|
||||
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}")
|
||||
|
||||
# 获取配置
|
||||
config = get_config(self.translator)
|
||||
|
||||
# 获取浏览器类型和路径
|
||||
browser_type = config.get('Browser', 'default_browser', fallback='chrome')
|
||||
browser_path = config.get('Browser', f'{browser_type}_path', fallback=utils_get_default_browser_path(browser_type))
|
||||
|
||||
if not browser_path or not os.path.exists(browser_path):
|
||||
if self.translator:
|
||||
print(f"{Fore.YELLOW}⚠️ {self.translator.get('email.browser_path_invalid', browser=browser_type) if self.translator else f'{browser_type} 路径无效,使用默认路径'}{Style.RESET_ALL}")
|
||||
browser_path = utils_get_default_browser_path(browser_type)
|
||||
|
||||
# 为了向后兼容,也检查 Chrome 路径
|
||||
if browser_type == 'chrome':
|
||||
chrome_path = config.get('Chrome', 'chromepath', fallback=None)
|
||||
if chrome_path and os.path.exists(chrome_path):
|
||||
browser_path = chrome_path
|
||||
|
||||
# 创建浏览器选项
|
||||
co = ChromiumOptions()
|
||||
|
||||
# 设置浏览器路径
|
||||
co.set_browser_path(browser_path)
|
||||
|
||||
# 记录浏览器信息
|
||||
if self.translator:
|
||||
print(f"{Fore.CYAN}🌐 {self.translator.get('email.using_browser', browser=browser_type, path=browser_path) if self.translator else f'使用 {browser_type} 浏览器: {browser_path}'}{Style.RESET_ALL}")
|
||||
|
||||
# Only use headless for non-OAuth operations
|
||||
if not hasattr(self, 'auth_type') or self.auth_type != 'oauth':
|
||||
co.set_argument("--headless=new")
|
||||
|
||||
if sys.platform == "linux":
|
||||
# Check if DISPLAY is set when not in headless mode
|
||||
if "--headless=new" not in co.arguments and not os.environ.get('DISPLAY'):
|
||||
print(f"{Fore.RED}❌ {self.translator.get('email.no_display_found') if self.translator else 'No display found. Make sure X server is running.'}{Style.RESET_ALL}")
|
||||
print(f"{Fore.YELLOW}ℹ️ {self.translator.get('email.try_export_display') if self.translator else 'Try: export DISPLAY=:0'}{Style.RESET_ALL}")
|
||||
return False
|
||||
|
||||
co.set_argument("--no-sandbox")
|
||||
co.set_argument("--disable-dev-shm-usage")
|
||||
co.set_argument("--disable-gpu")
|
||||
|
||||
# If running as root, try to use actual user's browser profile
|
||||
if os.geteuid() == 0:
|
||||
sudo_user = os.environ.get('SUDO_USER')
|
||||
if sudo_user:
|
||||
actual_home = f"/home/{sudo_user}"
|
||||
|
||||
# 根据浏览器类型选择配置文件夹
|
||||
profile_dirs = {
|
||||
'chrome': os.path.join(actual_home, ".config", "google-chrome"),
|
||||
'brave': os.path.join(actual_home, ".config", "BraveSoftware", "Brave-Browser"),
|
||||
'edge': os.path.join(actual_home, ".config", "microsoft-edge"),
|
||||
'firefox': os.path.join(actual_home, ".mozilla", "firefox")
|
||||
}
|
||||
|
||||
user_data_dir = profile_dirs.get(browser_type, profile_dirs['chrome'])
|
||||
|
||||
if os.path.exists(user_data_dir):
|
||||
print(f"{Fore.CYAN}ℹ️ {self.translator.get('email.using_browser_profile', browser=browser_type, user_data_dir=user_data_dir) if self.translator else f'Using {browser_type} profile from: {user_data_dir}'}{Style.RESET_ALL}")
|
||||
co.set_argument(f"--user-data-dir={user_data_dir}")
|
||||
|
||||
co.auto_port() # 自动设置端口
|
||||
|
||||
# 根据浏览器类型设置扩展参数
|
||||
extension_args = {
|
||||
'chrome': "--allow-extensions-in-incognito",
|
||||
'brave': "--allow-extensions-in-brave-incognito", # Brave 可能使用不同的参数
|
||||
'edge': "--allow-extensions-in-incognito",
|
||||
'firefox': None # Firefox 可能使用不同的方式加载扩展
|
||||
}
|
||||
|
||||
extension_arg = extension_args.get(browser_type, "--allow-extensions-in-incognito")
|
||||
|
||||
# 加载 uBlock 插件
|
||||
try:
|
||||
extension_path = self.get_extension_block()
|
||||
if extension_arg: # 如果有扩展参数
|
||||
co.set_argument(extension_arg)
|
||||
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}")
|
||||
|
||||
if sys.platform == "linux":
|
||||
browser_install_suggestions = {
|
||||
'chrome': "sudo apt install chromium-browser 或 sudo apt install google-chrome-stable",
|
||||
'brave': "sudo apt install brave-browser",
|
||||
'edge': "sudo apt install microsoft-edge-stable",
|
||||
'firefox': "sudo apt install firefox"
|
||||
}
|
||||
|
||||
suggestion = browser_install_suggestions.get(browser_type, browser_install_suggestions['chrome'])
|
||||
|
||||
print(f"{Fore.YELLOW}ℹ️ {self.translator.get('email.make_sure_browser_is_properly_installed', browser=browser_type) if self.translator else f'Make sure {browser_type} is properly installed'}{Style.RESET_ALL}")
|
||||
print(f"{Fore.YELLOW}ℹ️ {self.translator.get('email.try_install_browser') if self.translator else f'Try: {suggestion}'}{Style.RESET_ALL}")
|
||||
return False
|
||||
|
||||
def create_email(self):
|
||||
"""create temporary email"""
|
||||
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}")
|
||||
|
||||
# load blocked domains list
|
||||
self.blocked_domains = self.get_blocked_domains()
|
||||
|
||||
# visit website
|
||||
self.page.get("https://smailpro.com/")
|
||||
time.sleep(2)
|
||||
|
||||
# click create email button
|
||||
create_button = self.page.ele('xpath://button[@title="Create temporary email"]')
|
||||
if create_button:
|
||||
create_button.click()
|
||||
time.sleep(1)
|
||||
|
||||
# click Create button in popup
|
||||
modal_create_button = self.page.ele('xpath://button[contains(text(), "Create")]')
|
||||
if modal_create_button:
|
||||
modal_create_button.click()
|
||||
time.sleep(2)
|
||||
|
||||
# get email address - modify selector
|
||||
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: # check if it's a valid email address
|
||||
# check if domain is blocked
|
||||
domain = email.split('@')[1]
|
||||
if self.blocked_domains and domain in self.blocked_domains:
|
||||
if self.translator:
|
||||
print(f"{Fore.YELLOW}⚠️ {self.translator.get('email.domain_blocked')}: {domain}{Style.RESET_ALL}")
|
||||
else:
|
||||
print(f"{Fore.YELLOW}⚠️ 域名已被屏蔽: {domain},尝试重新创建邮箱{Style.RESET_ALL}")
|
||||
# create email again
|
||||
return self.create_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):
|
||||
"""close browser"""
|
||||
if self.page:
|
||||
self.page.quit()
|
||||
|
||||
def refresh_inbox(self):
|
||||
"""refresh inbox"""
|
||||
try:
|
||||
if self.translator:
|
||||
print(f"{Fore.CYAN}🔄 {self.translator.get('email.refreshing')}{Style.RESET_ALL}")
|
||||
else:
|
||||
print(f"{Fore.CYAN}🔄 正在刷新邮箱...{Style.RESET_ALL}")
|
||||
|
||||
# click refresh button
|
||||
refresh_button = self.page.ele('xpath://button[@id="refresh"]')
|
||||
if refresh_button:
|
||||
refresh_button.click()
|
||||
time.sleep(2) # wait for refresh to complete
|
||||
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:
|
||||
# find verification email - use more accurate selector
|
||||
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}")
|
||||
# use JavaScript to click element
|
||||
self.page.run_js('arguments[0].click()', email_div)
|
||||
time.sleep(2) # wait for email content to load
|
||||
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:
|
||||
# find verification code element
|
||||
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}")
|
||||
|
||||
# test refresh function
|
||||
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()
|
1052
oauth_auth.py
1052
oauth_auth.py
File diff suppressed because it is too large
Load Diff
@ -1,18 +0,0 @@
|
||||
{
|
||||
"manifest_version": 3,
|
||||
"name": "Turnstile Patcher",
|
||||
"version": "2.1",
|
||||
"content_scripts": [
|
||||
{
|
||||
"js": [
|
||||
"./script.js"
|
||||
],
|
||||
"matches": [
|
||||
"<all_urls>"
|
||||
],
|
||||
"run_at": "document_start",
|
||||
"all_frames": true,
|
||||
"world": "MAIN"
|
||||
}
|
||||
]
|
||||
}
|
@ -1,50 +0,0 @@
|
||||
function qSelector(selector) {
|
||||
return document.querySelector(selector);
|
||||
}
|
||||
|
||||
(function() {
|
||||
'use strict';
|
||||
var solved = false;
|
||||
var checkBoxClicked = false;
|
||||
var requestCount = 0;
|
||||
const MAX_ATTEMPTS = 1;
|
||||
const CHECK_BOX = ".recaptcha-checkbox-border";
|
||||
const AUDIO_BUTTON = "#recaptcha-audio-button";
|
||||
const PLAY_BUTTON = ".rc-audiochallenge-play-button .rc-button-default";
|
||||
const AUDIO_SOURCE = "#audio-source";
|
||||
const IMAGE_SELECT = "#rc-imageselect";
|
||||
const RESPONSE_FIELD = ".rc-audiochallenge-response-field";
|
||||
const AUDIO_ERROR_MESSAGE = ".rc-audiochallenge-error-message";
|
||||
const AUDIO_RESPONSE = "#audio-response";
|
||||
const RELOAD_BUTTON = "#recaptcha-reload-button";
|
||||
const RECAPTCHA_STATUS = "#recaptcha-accessible-status";
|
||||
const DOSCAPTCHA = ".rc-doscaptcha-body";
|
||||
const VERIFY_BUTTON = "#recaptcha-verify-button";
|
||||
var recaptchaInitialStatus = qSelector(RECAPTCHA_STATUS) ? qSelector(RECAPTCHA_STATUS).innerText : ""
|
||||
function isHidden(el) {
|
||||
return(el.offsetParent === null)
|
||||
}
|
||||
try {
|
||||
if(!checkBoxClicked && qSelector(CHECK_BOX) && !isHidden(qSelector(CHECK_BOX))) {
|
||||
//console.log("checkbox clicked");
|
||||
qSelector(CHECK_BOX).click();
|
||||
checkBoxClicked = true;
|
||||
}
|
||||
//Check if the captcha is solved
|
||||
if(qSelector(RECAPTCHA_STATUS) && (qSelector(RECAPTCHA_STATUS).innerText != recaptchaInitialStatus)) {
|
||||
solved = true;
|
||||
console.log("SOLVED");
|
||||
}
|
||||
if(requestCount > MAX_ATTEMPTS) {
|
||||
console.log("Attempted Max Retries. Stopping the solver");
|
||||
solved = true;
|
||||
}
|
||||
//Stop solving when Automated queries message is shown
|
||||
if(qSelector(DOSCAPTCHA) && qSelector(DOSCAPTCHA).innerText.length > 0) {
|
||||
console.log("Automated Queries Detected");
|
||||
}
|
||||
} catch(err) {
|
||||
console.log(err.message);
|
||||
console.log("An error occurred while solving. Stopping the solver.");
|
||||
}
|
||||
})();
|
@ -1,12 +0,0 @@
|
||||
function getRandomInt(min, max) {
|
||||
return Math.floor(Math.random() * (max - min + 1)) + min;
|
||||
}
|
||||
|
||||
// old method wouldn't work on 4k screens
|
||||
|
||||
let screenX = getRandomInt(800, 1200);
|
||||
let screenY = getRandomInt(400, 600);
|
||||
|
||||
Object.defineProperty(MouseEvent.prototype, 'screenX', { value: screenX });
|
||||
|
||||
Object.defineProperty(MouseEvent.prototype, 'screenY', { value: screenY });
|
Loading…
x
Reference in New Issue
Block a user