From da9d4a36483fb0853cf36e9a19cdef986f222020 Mon Sep 17 00:00:00 2001 From: Pin Studios Date: Wed, 16 Apr 2025 10:29:12 +0800 Subject: [PATCH] Update version to 1.9.06 and remove deprecated cursor authentication and registration scripts --- .env | 4 +- PBlock/background.js | 5 - PBlock/block.js | 129 ----- PBlock/default_filters.js | 14 - PBlock/enabled16.png | Bin 850 -> 0 bytes PBlock/enabled48.png | Bin 3529 -> 0 bytes PBlock/manifest.json | 29 - PBlock/rules.json | 5 - build.spec | 15 - cursor_auth.py | 159 ----- cursor_register.py | 264 --------- cursor_register_github.py | 5 - cursor_register_google.py | 5 - cursor_register_manual.py | 271 --------- delete_cursor_google.py | 386 ------------- github_cursor_register.py | 701 ---------------------- main.py | 75 +-- new_signup.py | 692 ---------------------- new_tempemail.py | 393 ------------- oauth_auth.py | 1052 ---------------------------------- turnstilePatch/manifest.json | 18 - turnstilePatch/recaptcha.js | 50 -- turnstilePatch/script.js | 12 - 23 files changed, 21 insertions(+), 4263 deletions(-) delete mode 100644 PBlock/background.js delete mode 100644 PBlock/block.js delete mode 100644 PBlock/default_filters.js delete mode 100644 PBlock/enabled16.png delete mode 100644 PBlock/enabled48.png delete mode 100644 PBlock/manifest.json delete mode 100644 PBlock/rules.json delete mode 100644 cursor_auth.py delete mode 100644 cursor_register.py delete mode 100644 cursor_register_github.py delete mode 100644 cursor_register_google.py delete mode 100644 cursor_register_manual.py delete mode 100644 delete_cursor_google.py delete mode 100644 github_cursor_register.py delete mode 100644 new_signup.py delete mode 100644 new_tempemail.py delete mode 100644 oauth_auth.py delete mode 100644 turnstilePatch/manifest.json delete mode 100644 turnstilePatch/recaptcha.js delete mode 100644 turnstilePatch/script.js diff --git a/.env b/.env index 8449e55..bf897df 100644 --- a/.env +++ b/.env @@ -1,2 +1,2 @@ -version=1.9.05 -VERSION=1.9.05 +version=1.9.06 +VERSION=1.9.06 diff --git a/PBlock/background.js b/PBlock/background.js deleted file mode 100644 index e3d18ff..0000000 --- a/PBlock/background.js +++ /dev/null @@ -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'); \ No newline at end of file diff --git a/PBlock/block.js b/PBlock/block.js deleted file mode 100644 index 0e0e821..0000000 --- a/PBlock/block.js +++ /dev/null @@ -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); - } - } -); diff --git a/PBlock/default_filters.js b/PBlock/default_filters.js deleted file mode 100644 index 84e6f83..0000000 --- a/PBlock/default_filters.js +++ /dev/null @@ -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/*", -] diff --git a/PBlock/enabled16.png b/PBlock/enabled16.png deleted file mode 100644 index 7b6a3f2252b0bdc0fdad9c8cf1243e936a248e56..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 850 zcmV-Y1FigtP)nb9>J%;8HoQ7r}@`ryr>tIz8unlekW9696%bfU`S&{S!&66 zYE;U}GNt|!dUG_%Pd$9=;T#5t-uYe( z&q&ucYFA@UOiuPslIhH_(`DDQoV{_DN3}<)v9<9K4p(LCaBEam)R$7r7pL}5G2A)4 zBL?Vh>87iti-p?@qVCn-5TW?O5P^8N>R0z>x-uM09Q;q5E9RJ9oo29okddAdDt_g4 z>Krf-q-@jvU%YZ>h4JNardFp|ch?ztWrTy+i#WBi$nd!l45={wWkr*vb3xNvSO~kXu2CIQvk8g2&;W+!A-^ZolOXQ#A8Cx8~ z^<8FDvyAqP0uZWjd%%=J7G2*Z|2R+I3w<2zJ<7$OFLGkx1b3@rto*7!Zg%<2pg9r?u(&PO7?7)J&&qwcFKyY1b^ z>i-kodzMtTM|3LFHhm@_Z2=Tc91#vU}p{dOareVrVXNGiVn)b$alvWho zBFn{PuHC*yPzzM>YH+%cD$D=~CV&9;ytIebSnCJgmiKYhtG*dABQ!Zp0JxsZR=7pf zivDB^``kuy^P=Ff6cn06~aZ@e^Ly!wft=NQGokKt^$`qhWM|1YQCZ}qojZ(g zZbG?OL<|5rZZCJpp=p9FBH-45KqZj<#xpOe=oS^-H)#i^1J3|&g2P`l(Sf?s_h&zKH5* z^~BbIu5=d%J~=>3XA3(zchK3}Nz{oFb)qAomR}@l@z|;%y(_T6Zzj?w_3iazABw<9 zu8kaw{HOJ8rJ9i#R+OGh57p6X?)c&z+&=Gi67j^RlAZ|dJ?(5gyp?AUJpAE9~=lWT_a5X=>?q}3jj2*di#k7)X+*E%PDKEvI<9jg1;K)#P z3;61n*_>S*iiVzbtm8T2;Fx@~m491_@A~*|K24B}{IkiLdq*#@zWVg%`uWD9Z}8~V zj}o@w@tOPy2-y(JYnS7z&+Ert#~O_VdS^D2B^%B+TlTdwe9y=C zeS&l_*Y?@X1`{5h`HIq=>1Or9)jWFjqn|tRGqG&OGJ3PUyz%iHL~NvZPUN_p9M7Ay zIcZV`lQP&DU!8%Qb#XH;ZpQtQ3Cz{QG;;p z10qg@hn7A>O-T)d-r&d!0TsPHhy<7VWj=nHkI9CzWJ6gz$6Jk1#Bv}vz^VnSSUh#{ zc_qB<=r+32T}994SIuYjg4LwF)S2R8U;V$yNsgT4Fg9#)!cNpN&R0h-Q7JFQtg>0G zn!oD2lK=6ZA9K$u_we1dNc5u=>K!op_)DkG%N^8~1OdG*n8+ zgbLZKHI|(p?&SEu@q+yPs`<>Wm`%pZ6rKr!ANWf$erCQ=(YcDw9c?5Rim{fhN`Y08%hePV8mx$(J0BLJYP4I1b?$1~n6 z6POD`W%Ntx%Rj$VVVL~d-D}zO-X$zs;HDmhL$LotXG(beE zMP#NCPo|1WVfj?@!&y^OGa;F_o;DtS<6%w=oR}2(T#)0T-4C(py-h{Q+A#TPCDYij ze8afp0WOGLfE9~sQ6d*bsC0}qF#<-mSk1>+iCZ$RvXA;c;#)hvMN4N3?LF;mSh0b4 zI6fiyte@rKHy&owdz*-d^;7h`to{OI$QYm&TrF~?VFJNgS#H&sRK_@8L2EHpUfngSvr%)8z28v^1x`)MNkx@ zMpFpcQPL>NKyIK&_;B(tcfWEs`%dknDpG|JLsg`T7u#RtzSr&>BcJk8eCPG=@XY(q z5D&+3#3>?QTUN`46&tv0+SzN0f!qM&6f-$N(k5_%(~1s^RC9tK_?#R(StRWmH=iBq zNTELL#BY!OmNmQ96n4x(Z;%IfJ;>&Rn~6t?$#-YEsV%GJ7mdH*@@bc!l{~=7!ISvv zpE;3JqLMU{l@Cx(jvgfup`)jxNJ)J~Jx^Z$Bul0(Dau=ho!EMKE8lEFwa>9zGGE&L5Bip#^<-2&H^@T#%3?rFIl87g0YHVWB)J2mfpYl>1 z?LLZY+!5|71U6{PMzcqZb?p(c@`ur#!Zu82Und7XIWR`y?DE+(t!U!H>I+GxlR!S4 z9C5J5@C|WFRygGGOp4@JVA3~GxI9vkxVBMq%bF1-jHP8N*-0ybw~3k`&lCM{{wCcQTxDEiz{C(6qmFLSK_*tm-4RnDWi zv6)0XK{AsZcd1LJlPs)WNK<1I3#t};X7VQoPqMvz``8*>Y0dbVHwL{yj0qb|*bIsz z+s|~Mqql=C?{AsVz{2Wt4Kd4Mg4ws0hQgqRyE ze&O&t8@4?*Y%z}K;P?)LY(^OzEf;fRY(BVo+_^A}MN=2i)Y!y~(isIOy3$=Np1PRF zS3Z8uhhDAStvr3;>9I$TN)C8hMDn3jbz2ny0V;YDLqY;6tZ%MyIh{I9M{ftWG~7}g zhodmPWIBtcEaJ6euhG`i#ud}9D1_I!AnRwj|F!#h=hQothsulIiIuH_tj7ll1Y3P) zHCRxq07p#Dd>t9djUqO}q2wV3y+M}OE}zio%(9s@#2e_(_Vd`6AETk7;he|=toz?} zg&q8iqsEMD+^;*-(dyenHSD$4wmQ855 zp`w9X=iW+Hq-sK$v!Q8U6HWV?C~-^1to=lJ%y<3Go_KgB-)!uz7#TM+(ro5`Y})>r z_3iB8LtQHt5n=bS-E?QVxpMlI6Nb~7dHZCM@iVO3yN>34&4g{3uniaX5#t#G8|=wW z&ED;o`dL5bGu)(RM{(XSA~?P?zam-jdoyTe4Bx^CLN3VBo9$(J?Q$Nt;(?;d=}*DI zPY$wf?>bsKTSm&vQRMxwfBN_($5&=!*)i8oV)l-`WeOyq>UdS-%s&vc5qQa15JH=)yH4!TF|w9JRQQn zjPo=AC*&|^+MHWMq0m!75R?^n5>j4@l$WBRqJbM{-^j|kl`N=QKzX=)9EBt3%l2`o z>kvCW*uhI3FL5+^l!y}{=ETO_r5Vo*W=b>n9Q})rK7ilWI9RMhR1GF017I4 zLX6y#i{xHtyQz&_S#GQx;7oW=IW!l2{Fi~79pkJgVELJsd@(0R%!!c;avbP7!2Z+w zf&9cD&WQpI@YP4r!X;m2q;dkoppNd&xw&sTzVnA+hbF>VZz)9uMc?&Z|Ie*w@5kqx zz?kzE*SJM1)9C9}A-`)*R2q)L0ET8i;{QlRd-2XD4u>SRsC0B;za2z zQ1pF8HyCRgfz`mCNq6o8{tFy_2{Zt=0c9|mVH?68V2`442j@yPdX2CCrJ|Ams(~03 zQj#1n0CWLuYIGj~yHxcpgyh*H>kOO%?g4%W4hpma9|4O#lLN!(7UX3Nd)3!@M$H_A znTl4D|Ca#)Qi3E=j;ZKT42KE$WVjIe%-9cX&vX5Mou96;JyBhb00000NkvXXu0mjf D`ZwBO diff --git a/PBlock/manifest.json b/PBlock/manifest.json deleted file mode 100644 index a18cbdc..0000000 --- a/PBlock/manifest.json +++ /dev/null @@ -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://*/*" - ] -} diff --git a/PBlock/rules.json b/PBlock/rules.json deleted file mode 100644 index 42f7490..0000000 --- a/PBlock/rules.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "id": "ruleset_1", - "version": "1.0", - "rules": [] -} \ No newline at end of file diff --git a/build.spec b/build.spec index 3219556..8dba0ba 100644 --- a/build.spec +++ b/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=[], diff --git a/cursor_auth.py b/cursor_auth.py deleted file mode 100644 index 7e53a30..0000000 --- a/cursor_auth.py +++ /dev/null @@ -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}") diff --git a/cursor_register.py b/cursor_register.py deleted file mode 100644 index d65f68d..0000000 --- a/cursor_register.py +++ /dev/null @@ -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) \ No newline at end of file diff --git a/cursor_register_github.py b/cursor_register_github.py deleted file mode 100644 index b4ea935..0000000 --- a/cursor_register_github.py +++ /dev/null @@ -1,5 +0,0 @@ -from oauth_auth import main as oauth_main - -def main(translator=None): - """Handle GitHub OAuth registration""" - oauth_main('github', translator) \ No newline at end of file diff --git a/cursor_register_google.py b/cursor_register_google.py deleted file mode 100644 index 1da32f2..0000000 --- a/cursor_register_google.py +++ /dev/null @@ -1,5 +0,0 @@ -from oauth_auth import main as oauth_main - -def main(translator=None): - """Handle Google OAuth registration""" - oauth_main('google', translator) \ No newline at end of file diff --git a/cursor_register_manual.py b/cursor_register_manual.py deleted file mode 100644 index e0f8b3e..0000000 --- a/cursor_register_manual.py +++ /dev/null @@ -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) \ No newline at end of file diff --git a/delete_cursor_google.py b/delete_cursor_google.py deleted file mode 100644 index 3bffac9..0000000 --- a/delete_cursor_google.py +++ /dev/null @@ -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() \ No newline at end of file diff --git a/github_cursor_register.py b/github_cursor_register.py deleted file mode 100644 index dc7ce64..0000000 --- a/github_cursor_register.py +++ /dev/null @@ -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() diff --git a/main.py b/main.py index c3759db..9428b67 100644 --- a/main.py +++ b/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() diff --git a/new_signup.py b/new_signup.py deleted file mode 100644 index 906b007..0000000 --- a/new_signup.py +++ /dev/null @@ -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 \ No newline at end of file diff --git a/new_tempemail.py b/new_tempemail.py deleted file mode 100644 index a92486e..0000000 --- a/new_tempemail.py +++ /dev/null @@ -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() \ No newline at end of file diff --git a/oauth_auth.py b/oauth_auth.py deleted file mode 100644 index 4313041..0000000 --- a/oauth_auth.py +++ /dev/null @@ -1,1052 +0,0 @@ -# oauth_auth.py -import os -from colorama import Fore, Style, init -import time -import random -import webbrowser -import sys -import json -from DrissionPage import ChromiumPage, ChromiumOptions -from cursor_auth import CursorAuth -from utils import get_random_wait_time, get_default_browser_path -from config import get_config -import platform -from get_user_token import get_token_from_cookie - -# Initialize colorama -init() - -# Define emoji constants -EMOJI = { - 'START': '🚀', - 'OAUTH': '🔑', - 'SUCCESS': '✅', - 'ERROR': '❌', - 'WAIT': '⏳', - 'INFO': 'ℹ️', - 'WARNING': '⚠️' -} - -class OAuthHandler: - def __init__(self, translator=None, auth_type=None): - self.translator = translator - self.config = get_config(translator) - self.auth_type = auth_type - os.environ['BROWSER_HEADLESS'] = 'False' - self.browser = None - self.selected_profile = None - - def _get_available_profiles(self, user_data_dir): - """Get list of available Chrome profiles with their names""" - try: - profiles = [] - profile_names = {} - - # Read Local State file to get profile names - local_state_path = os.path.join(user_data_dir, 'Local State') - if os.path.exists(local_state_path): - with open(local_state_path, 'r', encoding='utf-8') as f: - local_state = json.load(f) - info_cache = local_state.get('profile', {}).get('info_cache', {}) - for profile_dir, info in info_cache.items(): - profile_dir = profile_dir.replace('\\', '/') - if profile_dir == 'Default': - profile_names['Default'] = info.get('name', 'Default') - elif profile_dir.startswith('Profile '): - profile_names[profile_dir] = info.get('name', profile_dir) - - # Get list of profile directories - for item in os.listdir(user_data_dir): - if item == 'Default' or (item.startswith('Profile ') and os.path.isdir(os.path.join(user_data_dir, item))): - profiles.append((item, profile_names.get(item, item))) - return sorted(profiles) - except Exception as e: - print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('chrome_profile.error_loading', error=str(e)) if self.translator else f'Error loading Chrome profiles: {e}'}{Style.RESET_ALL}") - return [] - - def _select_profile(self): - """Allow user to select a browser profile to use""" - try: - # 从配置中获取浏览器类型 - config = get_config(self.translator) - browser_type = config.get('Browser', 'default_browser', fallback='chrome') - browser_type_display = browser_type.capitalize() - - if self.translator: - # 动态使用浏览器类型 - print(f"{Fore.CYAN}{EMOJI['INFO']} {self.translator.get('browser_profile.select_profile', browser=browser_type_display)}{Style.RESET_ALL}") - print(f"{Fore.CYAN}{self.translator.get('browser_profile.profile_list', browser=browser_type_display)}{Style.RESET_ALL}") - else: - print(f"{Fore.CYAN}{EMOJI['INFO']} Select {browser_type_display} profile to use:{Style.RESET_ALL}") - print(f"Available {browser_type_display} profiles:") - - # Get the user data directory for the browser type - user_data_dir = self._get_user_data_directory() - - # Load available profiles from the selected browser type - try: - local_state_file = os.path.join(user_data_dir, "Local State") - if os.path.exists(local_state_file): - with open(local_state_file, 'r', encoding='utf-8') as f: - state_data = json.load(f) - profiles_data = state_data.get('profile', {}).get('info_cache', {}) - - # Create a list of available profiles - profiles = [] - for profile_id, profile_info in profiles_data.items(): - name = profile_info.get('name', profile_id) - # Mark the default profile - if profile_id.lower() == 'default': - name = f"{name} (Default)" - profiles.append((profile_id, name)) - - # Sort profiles by name - profiles.sort(key=lambda x: x[1]) - - # Show available profiles - if self.translator: - print(f"{Fore.CYAN}0. {self.translator.get('menu.exit')}{Style.RESET_ALL}") - else: - print(f"{Fore.CYAN}0. Exit{Style.RESET_ALL}") - - for i, (profile_id, name) in enumerate(profiles, 1): - print(f"{Fore.CYAN}{i}. {name}{Style.RESET_ALL}") - - # Get user's choice - max_choice = len(profiles) - choice_str = input(f"\n{Fore.CYAN}{self.translator.get('menu.input_choice', choices=f'0-{max_choice}') if self.translator else f'Please enter your choice (0-{max_choice})'}{Style.RESET_ALL}") - - try: - choice = int(choice_str) - if choice == 0: - return False - elif 1 <= choice <= max_choice: - selected_profile = profiles[choice-1][0] - self.selected_profile = selected_profile - - if self.translator: - print(f"{Fore.GREEN}{EMOJI['SUCCESS']} {self.translator.get('browser_profile.profile_selected', profile=selected_profile)}{Style.RESET_ALL}") - else: - print(f"{Fore.GREEN}{EMOJI['SUCCESS']} Selected profile: {selected_profile}{Style.RESET_ALL}") - return True - else: - if self.translator: - print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('browser_profile.invalid_selection')}{Style.RESET_ALL}") - else: - print(f"{Fore.RED}{EMOJI['ERROR']} Invalid selection. Please try again.{Style.RESET_ALL}") - return self._select_profile() - except ValueError: - if self.translator: - print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('browser_profile.invalid_selection')}{Style.RESET_ALL}") - else: - print(f"{Fore.RED}{EMOJI['ERROR']} Invalid selection. Please try again.{Style.RESET_ALL}") - return self._select_profile() - else: - # No Local State file, use Default profile - print(f"{Fore.YELLOW}{EMOJI['WARNING']} {self.translator.get('browser_profile.no_profiles', browser=browser_type_display) if self.translator else f'No {browser_type_display} profiles found'}{Style.RESET_ALL}") - self.selected_profile = "Default" - return True - - except Exception as e: - # Error loading profiles, use Default profile - print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('browser_profile.error_loading', error=str(e), browser=browser_type_display) if self.translator else f'Error loading {browser_type_display} profiles: {str(e)}'}{Style.RESET_ALL}") - self.selected_profile = "Default" - return True - - except Exception as e: - # General error, use Default profile - print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('oauth.profile_selection_error', error=str(e)) if self.translator else f'Error during profile selection: {str(e)}'}{Style.RESET_ALL}") - self.selected_profile = "Default" - return True - - def setup_browser(self): - """Setup browser for OAuth flow using selected profile""" - try: - print(f"{Fore.CYAN}{EMOJI['INFO']} {self.translator.get('oauth.initializing_browser_setup') if self.translator else 'Initializing browser setup...'}{Style.RESET_ALL}") - - # Platform-specific initialization - platform_name = platform.system().lower() - print(f"{Fore.CYAN}{EMOJI['INFO']} {self.translator.get('oauth.detected_platform', platform=platform_name) if self.translator else f'Detected platform: {platform_name}'}{Style.RESET_ALL}") - - # 从配置中获取浏览器类型 - config = get_config(self.translator) - browser_type = config.get('Browser', 'default_browser', fallback='chrome') - - # Get browser paths and user data directory - user_data_dir = self._get_user_data_directory() - browser_path = self._get_browser_path() - - if not browser_path: - error_msg = ( - f"{self.translator.get('oauth.no_compatible_browser_found') if self.translator else 'No compatible browser found. Please install Google Chrome or Chromium.'}" + - "\n" + - f"{self.translator.get('oauth.supported_browsers', platform=platform_name)}\n" + - "- Windows: Google Chrome, Chromium\n" + - "- macOS: Google Chrome, Chromium\n" + - "- Linux: Google Chrome, Chromium, google-chrome-stable" - ) - raise Exception(error_msg) - - print(f"{Fore.CYAN}{EMOJI['INFO']} {self.translator.get('oauth.found_browser_data_directory', path=user_data_dir) if self.translator else f'Found browser data directory: {user_data_dir}'}{Style.RESET_ALL}") - - # Show warning about closing browser first - 使用动态提示 - if self.translator: - warning_msg = self.translator.get('oauth.warning_browser_close', browser=browser_type) - else: - warning_msg = f'Warning: This will close all running {browser_type} processes' - - print(f"\n{Fore.YELLOW}{EMOJI['WARNING']} {warning_msg}{Style.RESET_ALL}") - - choice = input(f"{Fore.YELLOW} {self.translator.get('menu.continue_prompt', choices='y/N')} {Style.RESET_ALL}").lower() - if choice != 'y': - print(f"{Fore.YELLOW}{EMOJI['INFO']} {self.translator.get('menu.operation_cancelled_by_user') if self.translator else 'Operation cancelled by user'}{Style.RESET_ALL}") - return False - - # Kill existing browser processes - self._kill_browser_processes() - - # Let user select a profile - if not self._select_profile(): - print(f"{Fore.YELLOW}{EMOJI['INFO']} {self.translator.get('menu.operation_cancelled_by_user') if self.translator else 'Operation cancelled by user'}{Style.RESET_ALL}") - return False - - # Configure browser options - co = self._configure_browser_options(browser_path, user_data_dir, self.selected_profile) - - print(f"{Fore.CYAN}{EMOJI['INFO']} {self.translator.get('oauth.starting_browser', path=browser_path) if self.translator else f'Starting browser at: {browser_path}'}{Style.RESET_ALL}") - self.browser = ChromiumPage(co) - - # Verify browser launched successfully - if not self.browser: - raise Exception(f"{self.translator.get('oauth.browser_failed_to_start', error=str(e)) if self.translator else 'Failed to initialize browser instance'}") - - print(f"{Fore.GREEN}{EMOJI['SUCCESS']} {self.translator.get('oauth.browser_setup_completed') if self.translator else 'Browser setup completed successfully'}{Style.RESET_ALL}") - return True - - except Exception as e: - print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('oauth.browser_setup_failed', error=str(e)) if self.translator else f'Browser setup failed: {str(e)}'}{Style.RESET_ALL}") - if "DevToolsActivePort file doesn't exist" in str(e): - print(f"{Fore.YELLOW}{EMOJI['INFO']} {self.translator.get('oauth.try_running_without_sudo_admin') if self.translator else 'Try running without sudo/administrator privileges'}{Style.RESET_ALL}") - elif "Chrome failed to start" in str(e): - print(f"{Fore.YELLOW}{EMOJI['INFO']} {self.translator.get('oauth.make_sure_chrome_chromium_is_properly_installed') if self.translator else 'Make sure Chrome/Chromium is properly installed'}{Style.RESET_ALL}") - if platform_name == 'linux': - print(f"{Fore.YELLOW}{EMOJI['INFO']} {self.translator.get('oauth.try_install_chromium') if self.translator else 'Try: sudo apt install chromium-browser'}{Style.RESET_ALL}") - return False - - def _kill_browser_processes(self): - """Kill existing browser processes based on platform and browser type""" - try: - # 从配置中获取浏览器类型 - config = get_config(self.translator) - browser_type = config.get('Browser', 'default_browser', fallback='chrome') - browser_type = browser_type.lower() - - # 根据浏览器类型和平台定义要关闭的进程 - browser_processes = { - 'chrome': { - 'win': ['chrome.exe', 'chromium.exe'], - 'linux': ['chrome', 'chromium', 'chromium-browser', 'google-chrome-stable'], - 'mac': ['Chrome', 'Chromium'] - }, - 'brave': { - 'win': ['brave.exe'], - 'linux': ['brave', 'brave-browser'], - 'mac': ['Brave Browser'] - }, - 'edge': { - 'win': ['msedge.exe'], - 'linux': ['msedge'], - 'mac': ['Microsoft Edge'] - }, - 'firefox': { - 'win': ['firefox.exe'], - 'linux': ['firefox'], - 'mac': ['Firefox'] - }, - 'opera': { - 'win': ['opera.exe', 'launcher.exe'], - 'linux': ['opera'], - 'mac': ['Opera'] - } - } - - # 获取平台类型 - if os.name == 'nt': - platform_type = 'win' - elif sys.platform == 'darwin': - platform_type = 'mac' - else: - platform_type = 'linux' - - # 获取要关闭的进程列表 - processes = browser_processes.get(browser_type, browser_processes['chrome']).get(platform_type, []) - - if self.translator: - print(f"{Fore.CYAN}{EMOJI['INFO']} {self.translator.get('oauth.killing_browser_processes', browser=browser_type) if self.translator else f'Killing {browser_type} processes...'}{Style.RESET_ALL}") - - # 根据平台关闭进程 - if os.name == 'nt': # Windows - for proc in processes: - os.system(f'taskkill /f /im {proc} >nul 2>&1') - else: # Linux/Mac - for proc in processes: - os.system(f'pkill -f {proc} >/dev/null 2>&1') - - time.sleep(1) # Wait for processes to close - except Exception as e: - print(f"{Fore.YELLOW}{EMOJI['INFO']} {self.translator.get('oauth.warning_could_not_kill_existing_browser_processes', error=str(e)) if self.translator else f'Warning: Could not kill existing browser processes: {e}'}{Style.RESET_ALL}") - - def _get_user_data_directory(self): - """Get the default user data directory based on browser type and platform""" - try: - # 从配置中获取浏览器类型 - config = get_config(self.translator) - browser_type = config.get('Browser', 'default_browser', fallback='chrome') - browser_type = browser_type.lower() - - # 根据操作系统和浏览器类型获取用户数据目录 - if os.name == 'nt': # Windows - user_data_dirs = { - 'chrome': os.path.join(os.environ.get('LOCALAPPDATA', ''), 'Google', 'Chrome', 'User Data'), - 'brave': os.path.join(os.environ.get('LOCALAPPDATA', ''), 'BraveSoftware', 'Brave-Browser', 'User Data'), - 'edge': os.path.join(os.environ.get('LOCALAPPDATA', ''), 'Microsoft', 'Edge', 'User Data'), - 'firefox': os.path.join(os.environ.get('APPDATA', ''), 'Mozilla', 'Firefox', 'Profiles'), - 'opera': os.path.join(os.environ.get('APPDATA', ''), 'Opera Software', 'Opera Stable'), - 'operagx': os.path.join(os.environ.get('APPDATA', ''), 'Opera Software', 'Opera GX Stable') - } - elif sys.platform == 'darwin': # macOS - user_data_dirs = { - 'chrome': os.path.expanduser('~/Library/Application Support/Google/Chrome'), - 'brave': os.path.expanduser('~/Library/Application Support/BraveSoftware/Brave-Browser'), - 'edge': os.path.expanduser('~/Library/Application Support/Microsoft Edge'), - 'firefox': os.path.expanduser('~/Library/Application Support/Firefox/Profiles'), - 'opera': os.path.expanduser('~/Library/Application Support/com.operasoftware.Opera'), - 'operagx': os.path.expanduser('~/Library/Application Support/com.operasoftware.OperaGX') - } - else: # Linux - user_data_dirs = { - 'chrome': os.path.expanduser('~/.config/google-chrome'), - 'brave': os.path.expanduser('~/.config/BraveSoftware/Brave-Browser'), - 'edge': os.path.expanduser('~/.config/microsoft-edge'), - 'firefox': os.path.expanduser('~/.mozilla/firefox'), - 'opera': os.path.expanduser('~/.config/opera'), - 'operagx': os.path.expanduser('~/.config/opera-gx') - } - - # 获取选定浏览器的用户数据目录,如果找不到则使用 Chrome 的 - user_data_dir = user_data_dirs.get(browser_type) - - if user_data_dir and os.path.exists(user_data_dir): - print(f"{Fore.GREEN}{EMOJI['SUCCESS']} {self.translator.get('oauth.found_browser_user_data_dir', browser=browser_type, path=user_data_dir) if self.translator else f'Found {browser_type} user data directory: {user_data_dir}'}{Style.RESET_ALL}") - return user_data_dir - else: - print(f"{Fore.YELLOW}{EMOJI['WARNING']} {self.translator.get('oauth.user_data_dir_not_found', browser=browser_type, path=user_data_dir) if self.translator else f'{browser_type} user data directory not found at {user_data_dir}, will try Chrome instead'}{Style.RESET_ALL}") - return user_data_dirs['chrome'] # 回退到 Chrome 目录 - - except Exception as e: - print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('oauth.error_getting_user_data_directory', error=str(e)) if self.translator else f'Error getting user data directory: {e}'}{Style.RESET_ALL}") - # 在出错时提供一个默认目录 - if os.name == 'nt': - return os.path.join(os.environ.get('LOCALAPPDATA', ''), 'Google', 'Chrome', 'User Data') - elif sys.platform == 'darwin': - return os.path.expanduser('~/Library/Application Support/Google/Chrome') - else: - return os.path.expanduser('~/.config/google-chrome') - - def _get_browser_path(self): - """Get appropriate browser path based on platform and selected browser type""" - try: - # 从配置中获取浏览器类型 - config = get_config(self.translator) - browser_type = config.get('Browser', 'default_browser', fallback='chrome') - browser_type = browser_type.lower() - - # 首先检查配置中是否有明确指定的浏览器路径 - browser_path = config.get('Browser', f'{browser_type}_path', fallback=None) - if browser_path and os.path.exists(browser_path): - print(f"{Fore.GREEN}{EMOJI['SUCCESS']} {self.translator.get('oauth.using_configured_browser_path', browser=browser_type, path=browser_path) if self.translator else f'Using configured {browser_type} path: {browser_path}'}{Style.RESET_ALL}") - return browser_path - - # 尝试获取默认路径 - browser_path = get_default_browser_path(browser_type) - if browser_path and os.path.exists(browser_path): - return browser_path - - print(f"{Fore.YELLOW}{EMOJI['INFO']} {self.translator.get('oauth.searching_for_alternative_browser_installations') if self.translator else 'Searching for alternative browser installations...'}{Style.RESET_ALL}") - - # 如果未找到配置中指定的浏览器,则尝试查找其他兼容浏览器 - if os.name == 'nt': # Windows - possible_paths = [] - if browser_type == 'brave': - possible_paths = [ - os.path.join(os.environ.get('PROGRAMFILES', ''), 'BraveSoftware', 'Brave-Browser', 'Application', 'brave.exe'), - os.path.join(os.environ.get('PROGRAMFILES(X86)', ''), 'BraveSoftware', 'Brave-Browser', 'Application', 'brave.exe'), - os.path.join(os.environ.get('LOCALAPPDATA', ''), 'BraveSoftware', 'Brave-Browser', 'Application', 'brave.exe') - ] - elif browser_type == 'edge': - possible_paths = [ - os.path.join(os.environ.get('PROGRAMFILES', ''), 'Microsoft', 'Edge', 'Application', 'msedge.exe'), - os.path.join(os.environ.get('PROGRAMFILES(X86)', ''), 'Microsoft', 'Edge', 'Application', 'msedge.exe') - ] - elif browser_type == 'firefox': - possible_paths = [ - os.path.join(os.environ.get('PROGRAMFILES', ''), 'Mozilla Firefox', 'firefox.exe'), - os.path.join(os.environ.get('PROGRAMFILES(X86)', ''), 'Mozilla Firefox', 'firefox.exe') - ] - elif browser_type == 'opera': - possible_paths = [ - os.path.join(os.environ.get('PROGRAMFILES', ''), 'Opera', 'opera.exe'), - os.path.join(os.environ.get('PROGRAMFILES(X86)', ''), 'Opera', 'opera.exe'), - os.path.join(os.environ.get('LOCALAPPDATA', ''), 'Programs', 'Opera', 'launcher.exe'), - os.path.join(os.environ.get('LOCALAPPDATA', ''), 'Programs', 'Opera', 'opera.exe'), - os.path.join(os.environ.get('LOCALAPPDATA', ''), 'Programs', 'Opera GX', 'launcher.exe'), - os.path.join(os.environ.get('LOCALAPPDATA', ''), 'Programs', 'Opera GX', 'opera.exe') - ] - else: # 默认为 Chrome - possible_paths = [ - os.path.join(os.environ.get('PROGRAMFILES', ''), 'Google', 'Chrome', 'Application', 'chrome.exe'), - os.path.join(os.environ.get('PROGRAMFILES(X86)', ''), 'Google', 'Chrome', 'Application', 'chrome.exe'), - os.path.join(os.environ.get('LOCALAPPDATA', ''), 'Google', 'Chrome', 'Application', 'chrome.exe') - ] - - elif sys.platform == 'darwin': # macOS - possible_paths = [] - if browser_type == 'brave': - possible_paths = ['/Applications/Brave Browser.app/Contents/MacOS/Brave Browser'] - elif browser_type == 'edge': - possible_paths = ['/Applications/Microsoft Edge.app/Contents/MacOS/Microsoft Edge'] - elif browser_type == 'firefox': - possible_paths = ['/Applications/Firefox.app/Contents/MacOS/firefox'] - else: # 默认为 Chrome - possible_paths = ['/Applications/Google Chrome.app/Contents/MacOS/Google Chrome'] - - else: # Linux - possible_paths = [] - if browser_type == 'brave': - possible_paths = ['/usr/bin/brave-browser', '/usr/bin/brave'] - elif browser_type == 'edge': - possible_paths = ['/usr/bin/microsoft-edge'] - elif browser_type == 'firefox': - possible_paths = ['/usr/bin/firefox'] - else: # 默认为 Chrome - possible_paths = [ - '/usr/bin/google-chrome-stable', # 优先检查 google-chrome-stable - '/usr/bin/google-chrome', - '/usr/bin/chromium', - '/usr/bin/chromium-browser' - ] - - # 检查每个可能的路径 - for path in possible_paths: - if os.path.exists(path): - print(f"{Fore.GREEN}{EMOJI['SUCCESS']} {self.translator.get('oauth.found_browser_at', path=path) if self.translator else f'Found browser at: {path}'}{Style.RESET_ALL}") - return path - - # 如果找不到指定浏览器,则尝试使用 Chrome - if browser_type != 'chrome': - print(f"{Fore.YELLOW}{EMOJI['WARNING']} {self.translator.get('oauth.browser_not_found_trying_chrome', browser=browser_type) if self.translator else f'Could not find {browser_type}, trying Chrome instead'}{Style.RESET_ALL}") - return self._get_chrome_path() - - return None - - except Exception as e: - print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('oauth.error_finding_browser_path', error=str(e)) if self.translator else f'Error finding browser path: {e}'}{Style.RESET_ALL}") - return None - - def _configure_browser_options(self, browser_path, user_data_dir, active_profile): - """Configure browser options based on platform""" - try: - co = ChromiumOptions() - co.set_paths(browser_path=browser_path, user_data_path=user_data_dir) - co.set_argument(f'--profile-directory={active_profile}') - - # Basic options - co.set_argument('--no-first-run') - co.set_argument('--no-default-browser-check') - co.set_argument('--disable-gpu') - co.set_argument('--remote-debugging-port=9222') # 明确指定调试端口 - - # Platform-specific options - if sys.platform.startswith('linux'): - co.set_argument('--no-sandbox') - co.set_argument('--disable-dev-shm-usage') - co.set_argument('--disable-setuid-sandbox') - elif sys.platform == 'darwin': - co.set_argument('--disable-gpu-compositing') - elif os.name == 'nt': - co.set_argument('--disable-features=TranslateUI') - co.set_argument('--disable-features=RendererCodeIntegrity') - - return co - - except Exception as e: - print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('oauth.error_configuring_browser_options', error=str(e)) if self.translator else f'Error configuring browser options: {e}'}{Style.RESET_ALL}") - raise - - def handle_google_auth(self): - """Handle Google OAuth authentication""" - try: - print(f"{Fore.CYAN}{EMOJI['INFO']} {self.translator.get('oauth.google_start') if self.translator else 'Starting Google OAuth authentication...'}{Style.RESET_ALL}") - - # Setup browser - if not self.setup_browser(): - print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('oauth.browser_failed') if self.translator else 'Browser failed to initialize'}{Style.RESET_ALL}") - return False, None - - # Navigate to auth URL - try: - print(f"{Fore.CYAN}{EMOJI['INFO']} {self.translator.get('oauth.navigating_to_authentication_page') if self.translator else 'Navigating to authentication page...'}{Style.RESET_ALL}") - self.browser.get("https://authenticator.cursor.sh/sign-up") - time.sleep(get_random_wait_time(self.config, 'page_load_wait')) - - # Look for Google auth button - 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 and auth_btn.is_displayed(): - break - except: - continue - - if not auth_btn: - raise Exception("Could not find Google authentication button") - - # Click the button and wait for page load - print(f"{Fore.CYAN}{EMOJI['INFO']} {self.translator.get('oauth.starting_google_authentication') if self.translator else 'Starting Google authentication...'}{Style.RESET_ALL}") - auth_btn.click() - time.sleep(get_random_wait_time(self.config, 'page_load_wait')) - - # Check if we're on account selection page - if "accounts.google.com" in self.browser.url: - print(f"{Fore.CYAN}{EMOJI['INFO']} {self.translator.get('oauth.please_select_your_google_account_to_continue') if self.translator else 'Please select your Google account to continue...'}{Style.RESET_ALL}") - - # 获取配置中是否启用 alert 选项 - config = get_config(self.translator) - show_alert = config.getboolean('OAuth', 'show_selection_alert', fallback=False) - - if show_alert: - alert_message = self.translator.get('oauth.please_select_your_google_account_to_continue') if self.translator else 'Please select your Google account to continue with Cursor authentication' - try: - self.browser.run_js(f""" - alert('{alert_message}'); - """) - except: - pass # Alert is optional - - # Wait for authentication to complete - auth_info = self._wait_for_auth() - if not auth_info: - print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('oauth.timeout') if self.translator else 'Timeout'}{Style.RESET_ALL}") - return False, None - - print(f"{Fore.GREEN}{EMOJI['SUCCESS']} {self.translator.get('oauth.success') if self.translator else 'Success'}{Style.RESET_ALL}") - return True, auth_info - - except Exception as e: - print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('oauth.authentication_error', error=str(e)) if self.translator else f'Authentication error: {str(e)}'}{Style.RESET_ALL}") - return False, None - finally: - try: - if self.browser: - self.browser.quit() - except: - pass - - except Exception as e: - print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('oauth.failed', error=str(e))}{Style.RESET_ALL}") - return False, None - - def _wait_for_auth(self): - """Wait for authentication to complete and extract auth info""" - try: - max_wait = 300 # 5 minutes - start_time = time.time() - check_interval = 2 # Check every 2 seconds - - print(f"{Fore.CYAN}{EMOJI['WAIT']} {self.translator.get('oauth.waiting_for_authentication', timeout='5 minutes') if self.translator else 'Waiting for authentication (timeout: 5 minutes)'}{Style.RESET_ALL}") - - while time.time() - start_time < max_wait: - try: - # Check for authentication cookies - cookies = self.browser.cookies() - - for cookie in cookies: - if cookie.get("name") == "WorkosCursorSessionToken": - value = cookie.get("value", "") - token = get_token_from_cookie(value, self.translator) - if token: - # Get email from settings page - print(f"{Fore.CYAN}{EMOJI['INFO']} {self.translator.get('oauth.authentication_successful_getting_account_info') if self.translator else 'Authentication successful, getting account info...'}{Style.RESET_ALL}") - self.browser.get("https://www.cursor.com/settings") - time.sleep(3) - - email = None - 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('oauth.found_email', email=email) if self.translator else f'Found email: {email}'}{Style.RESET_ALL}") - except: - email = "user@cursor.sh" # Fallback email - - # Check usage count - try: - usage_element = self.browser.ele("css:div[class='flex flex-col gap-4 lg:flex-row'] div:nth-child(1) div:nth-child(1) span:nth-child(2)") - if usage_element: - usage_text = usage_element.text - print(f"{Fore.CYAN}{EMOJI['INFO']} {self.translator.get('oauth.usage_count', usage=usage_text) if self.translator else f'Usage count: {usage_text}'}{Style.RESET_ALL}") - - def check_usage_limits(usage_str): - try: - parts = usage_str.split('/') - if len(parts) != 2: - return False - current = int(parts[0].strip()) - limit = int(parts[1].strip()) - return (limit == 50 and current >= 50) or (limit == 150 and current >= 150) - except: - return False - - if check_usage_limits(usage_text): - print(f"{Fore.YELLOW}{EMOJI['INFO']} {self.translator.get('oauth.account_has_reached_maximum_usage', deleting='deleting') if self.translator else 'Account has reached maximum usage, deleting...'}{Style.RESET_ALL}") - if self._delete_current_account(): - print(f"{Fore.CYAN}{EMOJI['INFO']} {self.translator.get('oauth.starting_new_authentication_process') if self.translator else 'Starting new authentication process...'}{Style.RESET_ALL}") - if self.auth_type == "google": - return self.handle_google_auth() - else: - return self.handle_github_auth() - else: - print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('oauth.failed_to_delete_expired_account') if self.translator else 'Failed to delete expired account'}{Style.RESET_ALL}") - else: - print(f"{Fore.GREEN}{EMOJI['SUCCESS']} {self.translator.get('oauth.account_is_still_valid', usage=usage_text) if self.translator else f'Account is still valid (Usage: {usage_text})'}{Style.RESET_ALL}") - except Exception as e: - print(f"{Fore.YELLOW}{EMOJI['INFO']} {self.translator.get('oauth.could_not_check_usage_count', error=str(e)) if self.translator else f'Could not check usage count: {str(e)}'}{Style.RESET_ALL}") - - return {"email": email, "token": token} - - # Also check URL as backup - if "cursor.com/settings" in self.browser.url: - print(f"{Fore.CYAN}{EMOJI['INFO']} {self.translator.get('oauth.detected_successful_login') if self.translator else 'Detected successful login'}{Style.RESET_ALL}") - - except Exception as e: - print(f"{Fore.YELLOW}{EMOJI['INFO']} {self.translator.get('oauth.waiting_for_authentication', error=str(e)) if self.translator else f'Waiting for authentication... ({str(e)})'}{Style.RESET_ALL}") - - time.sleep(check_interval) - - print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('oauth.authentication_timeout') if self.translator else 'Authentication timeout'}{Style.RESET_ALL}") - return None - - except Exception as e: - print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('oauth.error_waiting_for_authentication', error=str(e)) if self.translator else f'Error while waiting for authentication: {str(e)}'}{Style.RESET_ALL}") - return None - - def handle_github_auth(self): - """Handle GitHub OAuth authentication""" - try: - print(f"{Fore.CYAN}{EMOJI['INFO']} {self.translator.get('oauth.github_start')}{Style.RESET_ALL}") - - # Setup browser - if not self.setup_browser(): - print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('oauth.browser_failed', error=str(e)) if self.translator else 'Browser failed to initialize'}{Style.RESET_ALL}") - return False, None - - # Navigate to auth URL - try: - print(f"{Fore.CYAN}{EMOJI['INFO']} {self.translator.get('oauth.navigating_to_authentication_page') if self.translator else 'Navigating to authentication page...'}{Style.RESET_ALL}") - self.browser.get("https://authenticator.cursor.sh/sign-up") - time.sleep(get_random_wait_time(self.config, 'page_load_wait')) - - # Look for GitHub auth button - selectors = [ - "//a[contains(@href,'GitHubOAuth')]", - "//a[contains(@class,'auth-method-button') and contains(@href,'GitHubOAuth')]", - "(//a[contains(@class,'auth-method-button')])[2]" # Second 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 and auth_btn.is_displayed(): - break - except: - continue - - if not auth_btn: - raise Exception("Could not find GitHub authentication button") - - # Click the button and wait for page load - print(f"{Fore.CYAN}{EMOJI['INFO']} {self.translator.get('oauth.starting_github_authentication') if self.translator else 'Starting GitHub authentication...'}{Style.RESET_ALL}") - auth_btn.click() - time.sleep(get_random_wait_time(self.config, 'page_load_wait')) - - # Wait for authentication to complete - auth_info = self._wait_for_auth() - if not auth_info: - print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('oauth.timeout') if self.translator else 'Timeout'}{Style.RESET_ALL}") - return False, None - - print(f"{Fore.GREEN}{EMOJI['SUCCESS']} {self.translator.get('oauth.success')}{Style.RESET_ALL}") - return True, auth_info - - except Exception as e: - print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('oauth.authentication_error', error=str(e)) if self.translator else f'Authentication error: {str(e)}'}{Style.RESET_ALL}") - return False, None - finally: - try: - if self.browser: - self.browser.quit() - except: - pass - - except Exception as e: - print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('oauth.failed', error=str(e))}{Style.RESET_ALL}") - return False, None - - def _handle_oauth(self, auth_type): - """Handle OAuth authentication for both Google and GitHub - - Args: - auth_type (str): Type of authentication ('google' or 'github') - """ - try: - if not self.setup_browser(): - return False, None - - # Navigate to auth URL - self.browser.get("https://authenticator.cursor.sh/sign-up") - time.sleep(get_random_wait_time(self.config, 'page_load_wait')) - - # Set selectors based on auth type - if auth_type == "google": - selectors = [ - "//a[@class='rt-reset rt-BaseButton rt-r-size-3 rt-variant-surface rt-high-contrast rt-Button auth-method-button_AuthMethodButton__irESX'][contains(@href,'GoogleOAuth')]", - "(//a[@class='rt-reset rt-BaseButton rt-r-size-3 rt-variant-surface rt-high-contrast rt-Button auth-method-button_AuthMethodButton__irESX'])[1]" - ] - else: # github - selectors = [ - "(//a[@class='rt-reset rt-BaseButton rt-r-size-3 rt-variant-surface rt-high-contrast rt-Button auth-method-button_AuthMethodButton__irESX'])[2]" - ] - - # Wait for the button to be available - auth_btn = None - max_button_wait = 30 # 30 seconds - button_start_time = time.time() - - while time.time() - button_start_time < max_button_wait: - for selector in selectors: - try: - auth_btn = self.browser.ele(f"xpath:{selector}", timeout=1) - if auth_btn and auth_btn.is_displayed(): - break - except: - continue - if auth_btn: - break - time.sleep(1) - - if auth_btn: - # Click the button and wait for page load - auth_btn.click() - time.sleep(get_random_wait_time(self.config, 'page_load_wait')) - - # Check if we're on account selection page - if auth_type == "google" and "accounts.google.com" in self.browser.url: - alert_message = self.translator.get('oauth.please_select_your_google_account_to_continue') if self.translator else 'Please select your Google account to continue with Cursor authentication' - try: - self.browser.run_js(f""" - alert('{alert_message}'); - """) - except Exception as e: - print(f"{Fore.YELLOW}{EMOJI['INFO']} {self.translator.get('oauth.alert_display_failed', error=str(e)) if self.translator else f'Alert display failed: {str(e)}'}{Style.RESET_ALL}") - print(f"{Fore.CYAN}{EMOJI['INFO']} {self.translator.get('oauth.please_select_your_google_account_manually_to_continue_with_cursor_authentication') if self.translator else 'Please select your Google account manually to continue with Cursor authentication...'}{Style.RESET_ALL}") - - print(f"{Fore.CYAN}{EMOJI['INFO']} {self.translator.get('oauth.waiting_for_authentication_to_complete') if self.translator else 'Waiting for authentication to complete...'}{Style.RESET_ALL}") - - # Wait for authentication to complete - max_wait = 300 # 5 minutes - start_time = time.time() - last_url = self.browser.url - - print(f"{Fore.CYAN}{EMOJI['WAIT']} {self.translator.get('oauth.checking_authentication_status') if self.translator else 'Checking authentication status...'}{Style.RESET_ALL}") - - while time.time() - start_time < max_wait: - try: - # Check for authentication cookies - cookies = self.browser.cookies() - - for cookie in cookies: - if cookie.get("name") == "WorkosCursorSessionToken": - value = cookie.get("value", "") - token = get_token_from_cookie(value, self.translator) - if token: - print(f"{Fore.GREEN}{EMOJI['SUCCESS']} {self.translator.get('oauth.authentication_successful') if self.translator else 'Authentication successful!'}{Style.RESET_ALL}") - # Navigate to settings page - print(f"{Fore.CYAN}{EMOJI['INFO']} {self.translator.get('oauth.navigating_to_settings_page') if self.translator else 'Navigating to settings page...'}{Style.RESET_ALL}") - self.browser.get("https://www.cursor.com/settings") - time.sleep(3) # Wait for settings page to load - - # Get email from settings page - 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: - actual_email = email_element.text - print(f"{Fore.CYAN}{EMOJI['INFO']} {self.translator.get('oauth.found_email', email=actual_email) if self.translator else f'Found email: {actual_email}'}{Style.RESET_ALL}") - except Exception as e: - print(f"{Fore.YELLOW}{EMOJI['INFO']} {self.translator.get('oauth.could_not_find_email', error=str(e)) if self.translator else f'Could not find email: {str(e)}'}{Style.RESET_ALL}") - actual_email = "user@cursor.sh" - - # Check usage count - try: - usage_element = self.browser.ele("css:div[class='flex flex-col gap-4 lg:flex-row'] div:nth-child(1) div:nth-child(1) span:nth-child(2)") - if usage_element: - usage_text = usage_element.text - print(f"{Fore.CYAN}{EMOJI['INFO']} {self.translator.get('oauth.usage_count', usage=usage_text) if self.translator else f'Usage count: {usage_text}'}{Style.RESET_ALL}") - - def check_usage_limits(usage_str): - try: - parts = usage_str.split('/') - if len(parts) != 2: - return False - current = int(parts[0].strip()) - limit = int(parts[1].strip()) - return (limit == 50 and current >= 50) or (limit == 150 and current >= 150) - except: - return False - - if check_usage_limits(usage_text): - print(f"{Fore.YELLOW}{EMOJI['INFO']} {self.translator.get('oauth.account_has_reached_maximum_usage', deleting='deleting') if self.translator else 'Account has reached maximum usage, deleting...'}{Style.RESET_ALL}") - if self._delete_current_account(): - print(f"{Fore.CYAN}{EMOJI['INFO']} {self.translator.get('oauth.starting_new_authentication_process') if self.translator else 'Starting new authentication process...'}{Style.RESET_ALL}") - if self.auth_type == "google": - return self.handle_google_auth() - else: - return self.handle_github_auth() - else: - print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('oauth.failed_to_delete_expired_account') if self.translator else 'Failed to delete expired account'}{Style.RESET_ALL}") - else: - print(f"{Fore.GREEN}{EMOJI['SUCCESS']} {self.translator.get('oauth.account_is_still_valid', usage=usage_text) if self.translator else f'Account is still valid (Usage: {usage_text})'}{Style.RESET_ALL}") - except Exception as e: - print(f"{Fore.YELLOW}{EMOJI['INFO']} {self.translator.get('oauth.could_not_check_usage_count', error=str(e)) if self.translator else f'Could not check usage count: {str(e)}'}{Style.RESET_ALL}") - - # Remove the browser stay open prompt and input wait - return True, {"email": actual_email, "token": token} - - # Also check URL as backup - current_url = self.browser.url - if "cursor.com/settings" in current_url: - print(f"{Fore.GREEN}{EMOJI['SUCCESS']} {self.translator.get('oauth.already_on_settings_page') if self.translator else 'Already on settings page!'}{Style.RESET_ALL}") - time.sleep(1) - cookies = self.browser.cookies() - for cookie in cookies: - if cookie.get("name") == "WorkosCursorSessionToken": - value = cookie.get("value", "") - token = get_token_from_cookie(value, self.translator) - if token: - # Get email and check usage here too - 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: - actual_email = email_element.text - print(f"{Fore.CYAN}{EMOJI['INFO']} {self.translator.get('oauth.found_email', email=actual_email) if self.translator else f'Found email: {actual_email}'}{Style.RESET_ALL}") - except Exception as e: - print(f"{Fore.YELLOW}{EMOJI['INFO']} {self.translator.get('oauth.could_not_find_email', error=str(e)) if self.translator else f'Could not find email: {str(e)}'}{Style.RESET_ALL}") - actual_email = "user@cursor.sh" - - # Check usage count - try: - usage_element = self.browser.ele("css:div[class='flex flex-col gap-4 lg:flex-row'] div:nth-child(1) div:nth-child(1) span:nth-child(2)") - if usage_element: - usage_text = usage_element.text - print(f"{Fore.CYAN}{EMOJI['INFO']} {self.translator.get('oauth.usage_count', usage=usage_text) if self.translator else f'Usage count: {usage_text}'}{Style.RESET_ALL}") - - def check_usage_limits(usage_str): - try: - parts = usage_str.split('/') - if len(parts) != 2: - return False - current = int(parts[0].strip()) - limit = int(parts[1].strip()) - return (limit == 50 and current >= 50) or (limit == 150 and current >= 150) - except: - return False - - if check_usage_limits(usage_text): - print(f"{Fore.YELLOW}{EMOJI['INFO']} {self.translator.get('oauth.account_has_reached_maximum_usage', deleting='deleting') if self.translator else 'Account has reached maximum usage, deleting...'}{Style.RESET_ALL}") - if self._delete_current_account(): - print(f"{Fore.CYAN}{EMOJI['INFO']} {self.translator.get('oauth.starting_new_authentication_process') if self.translator else 'Starting new authentication process...'}{Style.RESET_ALL}") - if self.auth_type == "google": - return self.handle_google_auth() - else: - return self.handle_github_auth() - else: - print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('oauth.failed_to_delete_expired_account') if self.translator else 'Failed to delete expired account'}{Style.RESET_ALL}") - else: - print(f"{Fore.GREEN}{EMOJI['SUCCESS']} {self.translator.get('oauth.account_is_still_valid', usage=usage_text) if self.translator else f'Account is still valid (Usage: {usage_text})'}{Style.RESET_ALL}") - except Exception as e: - print(f"{Fore.YELLOW}{EMOJI['INFO']} {self.translator.get('oauth.could_not_check_usage_count', error=str(e)) if self.translator else f'Could not check usage count: {str(e)}'}{Style.RESET_ALL}") - - # Remove the browser stay open prompt and input wait - return True, {"email": actual_email, "token": token} - elif current_url != last_url: - print(f"{Fore.CYAN}{EMOJI['INFO']} {self.translator.get('oauth.page_changed_checking_auth') if self.translator else 'Page changed, checking auth...'}{Style.RESET_ALL}") - last_url = current_url - time.sleep(get_random_wait_time(self.config, 'page_load_wait')) - except Exception as e: - print(f"{Fore.YELLOW}{EMOJI['INFO']} {self.translator.get('oauth.status_check_error', error=str(e)) if self.translator else f'Status check error: {str(e)}'}{Style.RESET_ALL}") - time.sleep(1) - continue - time.sleep(1) - - print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('oauth.authentication_timeout') if self.translator else 'Authentication timeout'}{Style.RESET_ALL}") - return False, None - - print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('oauth.authentication_button_not_found') if self.translator else 'Authentication button not found'}{Style.RESET_ALL}") - return False, None - - except Exception as e: - print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('oauth.authentication_failed', error=str(e)) if self.translator else f'Authentication failed: {str(e)}'}{Style.RESET_ALL}") - return False, None - finally: - if self.browser: - self.browser.quit() - - def _extract_auth_info(self): - """Extract authentication information after successful OAuth""" - try: - # Get cookies with retry - max_retries = 3 - for attempt in range(max_retries): - try: - cookies = self.browser.cookies() - if cookies: - break - time.sleep(1) - except: - if attempt == max_retries - 1: - raise - time.sleep(1) - - # Debug cookie information - print(f"{Fore.CYAN}{EMOJI['INFO']} {self.translator.get('oauth.found_cookies', count=len(cookies)) if self.translator else f'Found {len(cookies)} cookies'}{Style.RESET_ALL}") - - email = None - token = None - - for cookie in cookies: - name = cookie.get("name", "") - if name == "WorkosCursorSessionToken": - try: - value = cookie.get("value", "") - token = get_token_from_cookie(value, self.translator) - except Exception as e: - error_message = f'Failed to extract auth info: {str(e)}' if not self.translator else self.translator.get('oauth.failed_to_extract_auth_info', error=str(e)) - print(f"{Fore.RED}{EMOJI['ERROR']} {error_message}{Style.RESET_ALL}") - elif name == "cursor_email": - email = cookie.get("value") - - if email and token: - print(f"{Fore.GREEN}{EMOJI['SUCCESS']} {self.translator.get('oauth.authentication_successful', email=email) if self.translator else f'Authentication successful - Email: {email}'}{Style.RESET_ALL}") - return True, {"email": email, "token": token} - else: - missing = [] - if not email: - missing.append("email") - if not token: - missing.append("token") - error_message = f"Missing authentication data: {', '.join(missing)}" if not self.translator else self.translator.get('oauth.missing_authentication_data', data=', '.join(missing)) - print(f"{Fore.RED}{EMOJI['ERROR']} {error_message}{Style.RESET_ALL}") - return False, None - - except Exception as e: - error_message = f'Failed to extract auth info: {str(e)}' if not self.translator else self.translator.get('oauth.failed_to_extract_auth_info', error=str(e)) - print(f"{Fore.RED}{EMOJI['ERROR']} {error_message}{Style.RESET_ALL}") - return False, None - - def _delete_current_account(self): - """Delete the current account using the API""" - try: - delete_js = """ - function deleteAccount() { - return new Promise((resolve, reject) => { - fetch('https://www.cursor.com/api/dashboard/delete-account', { - method: 'POST', - headers: { - 'Content-Type': 'application/json' - }, - credentials: 'include' - }) - .then(response => { - if (response.status === 200) { - resolve('Account deleted successfully'); - } else { - reject('Failed to delete account: ' + response.status); - } - }) - .catch(error => { - reject('Error: ' + error); - }); - }); - } - return deleteAccount(); - """ - - result = self.browser.run_js(delete_js) - print(f"{Fore.GREEN}{EMOJI['SUCCESS']} Delete account result: {result}{Style.RESET_ALL}") - - # Navigate back to auth page - print(f"{Fore.CYAN}{EMOJI['INFO']} {self.translator.get('oauth.redirecting_to_authenticator_cursor_sh') if self.translator else 'Redirecting to authenticator.cursor.sh...'}{Style.RESET_ALL}") - self.browser.get("https://authenticator.cursor.sh/sign-up") - time.sleep(get_random_wait_time(self.config, 'page_load_wait')) - - return True - - except Exception as e: - error_message = f'Failed to delete account: {str(e)}' if not self.translator else self.translator.get('oauth.failed_to_delete_account', error=str(e)) - print(f"{Fore.RED}{EMOJI['ERROR']} {error_message}{Style.RESET_ALL}") - return False - -def main(auth_type, translator=None): - """Main function to handle OAuth authentication - - Args: - auth_type (str): Type of authentication ('google' or 'github') - translator: Translator instance for internationalization - """ - handler = OAuthHandler(translator, auth_type) - - if auth_type.lower() == 'google': - print(f"{Fore.CYAN}{EMOJI['INFO']} {translator.get('oauth.google_start') if translator else 'Google start'}{Style.RESET_ALL}") - success, auth_info = handler.handle_google_auth() - elif auth_type.lower() == 'github': - print(f"{Fore.CYAN}{EMOJI['INFO']} {translator.get('oauth.github_start') if translator else 'Github start'}{Style.RESET_ALL}") - success, auth_info = handler.handle_github_auth() - else: - print(f"{Fore.RED}{EMOJI['ERROR']} {translator.get('oauth.invalid_authentication_type') if translator else 'Invalid authentication type'}{Style.RESET_ALL}") - return False - - if success and auth_info: - # Update Cursor authentication - auth_manager = CursorAuth(translator) - if auth_manager.update_auth( - email=auth_info["email"], - access_token=auth_info["token"], - refresh_token=auth_info["token"] - ): - print(f"{Fore.GREEN}{EMOJI['SUCCESS']} {translator.get('oauth.auth_update_success') if translator else 'Auth update success'}{Style.RESET_ALL}") - # Close the browser after successful authentication - if handler.browser: - handler.browser.quit() - print(f"{Fore.CYAN}{EMOJI['INFO']} {translator.get('oauth.browser_closed') if translator else 'Browser closed'}{Style.RESET_ALL}") - return True - else: - print(f"{Fore.RED}{EMOJI['ERROR']} {translator.get('oauth.auth_update_failed') if translator else 'Auth update failed'}{Style.RESET_ALL}") - - return False \ No newline at end of file diff --git a/turnstilePatch/manifest.json b/turnstilePatch/manifest.json deleted file mode 100644 index 3f4c606..0000000 --- a/turnstilePatch/manifest.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "manifest_version": 3, - "name": "Turnstile Patcher", - "version": "2.1", - "content_scripts": [ - { - "js": [ - "./script.js" - ], - "matches": [ - "" - ], - "run_at": "document_start", - "all_frames": true, - "world": "MAIN" - } - ] -} \ No newline at end of file diff --git a/turnstilePatch/recaptcha.js b/turnstilePatch/recaptcha.js deleted file mode 100644 index 40cb695..0000000 --- a/turnstilePatch/recaptcha.js +++ /dev/null @@ -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."); - } -})(); \ No newline at end of file diff --git a/turnstilePatch/script.js b/turnstilePatch/script.js deleted file mode 100644 index a46d798..0000000 --- a/turnstilePatch/script.js +++ /dev/null @@ -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 }); \ No newline at end of file