mirror of
https://github.com/yeongpin/cursor-free-vip.git
synced 2025-08-02 20:47:35 +08:00
fix & optimize
This commit is contained in:
parent
887239d80c
commit
1cc93ffc22
@ -1,5 +0,0 @@
|
||||
fr.nf
|
||||
yopmail.com
|
||||
1s.fr
|
||||
xl.cx
|
||||
fr.cr
|
48
browser.py
48
browser.py
@ -32,11 +32,6 @@ class BrowserManager:
|
||||
extension_block_path = self.get_extension_block()
|
||||
co.add_extension(extension_block_path)
|
||||
co.set_argument("--allow-extensions-in-incognito")
|
||||
|
||||
extension_recaptcha_path = self.get_extension_recaptcha()
|
||||
co.add_extension(extension_recaptcha_path)
|
||||
co.set_argument("--allow-extensions-in-incognito")
|
||||
|
||||
except FileNotFoundError as e:
|
||||
logging.warning(f"警告: {e}")
|
||||
|
||||
@ -47,35 +42,6 @@ class BrowserManager:
|
||||
|
||||
# 基本设置
|
||||
co.set_pref("credentials_enable_service", False)
|
||||
co.set_pref("profile.password_manager_enabled", False)
|
||||
|
||||
# 禁用自动化标志
|
||||
co.set_pref("useAutomationExtension", False)
|
||||
co.set_pref("excludeSwitches", ["enable-automation"])
|
||||
|
||||
# WebGL 和 GPU 设置
|
||||
co.set_pref("webgl.disabled", False)
|
||||
co.set_pref("webgl.enable_webgl2", True)
|
||||
|
||||
# 设置语言和地区
|
||||
co.set_pref("intl.accept_languages", "en-US,en")
|
||||
|
||||
# 基本命令行参数
|
||||
co.set_argument("--disable-blink-features=AutomationControlled")
|
||||
co.set_argument("--hide-crash-restore-bubble")
|
||||
co.set_argument("--no-first-run")
|
||||
co.set_argument("--no-default-browser-check")
|
||||
co.set_argument("--disable-popup-blocking")
|
||||
|
||||
# 性能和稳定性参数
|
||||
co.set_argument("--disable-dev-shm-usage")
|
||||
co.set_argument("--disable-gpu")
|
||||
co.set_argument("--no-sandbox")
|
||||
co.set_argument("--ignore-certificate-errors")
|
||||
|
||||
# WebGL 相关参数
|
||||
co.set_argument("--use-gl=swiftshader")
|
||||
co.set_argument("--enable-webgl")
|
||||
|
||||
# 随机端口
|
||||
co.auto_port()
|
||||
@ -87,7 +53,6 @@ class BrowserManager:
|
||||
elif sys.platform == "win32": # Windows
|
||||
co.set_argument("--disable-software-rasterizer")
|
||||
|
||||
|
||||
# 设置窗口大小
|
||||
window_width = random.randint(1024, 1920)
|
||||
window_height = random.randint(768, 1080)
|
||||
@ -121,19 +86,6 @@ class BrowserManager:
|
||||
|
||||
return extension_path
|
||||
|
||||
def get_extension_recaptcha(self):
|
||||
"""获取插件路径"""
|
||||
root_dir = os.getcwd()
|
||||
extension_path = os.path.join(root_dir, "recaptchaPatch")
|
||||
|
||||
if hasattr(sys, "_MEIPASS"):
|
||||
extension_path = os.path.join(sys._MEIPASS, "recaptchaPatch")
|
||||
|
||||
if not os.path.exists(extension_path):
|
||||
raise FileNotFoundError(f"插件不存在: {extension_path}")
|
||||
|
||||
return extension_path
|
||||
|
||||
def quit(self):
|
||||
"""关闭浏览器"""
|
||||
if self.browser:
|
||||
|
@ -24,7 +24,6 @@ a = Analysis(
|
||||
binaries=[],
|
||||
datas=[
|
||||
('turnstilePatch', 'turnstilePatch'),
|
||||
('recaptchaPatch', 'recaptchaPatch'),
|
||||
('uBlock0.chromium', 'uBlock0.chromium'),
|
||||
('locales', 'locales'),
|
||||
('cursor_auth.py', '.'),
|
||||
@ -32,8 +31,7 @@ a = Analysis(
|
||||
('cursor_register.py', '.'),
|
||||
('browser.py', '.'),
|
||||
('control.py', '.'),
|
||||
('.env', '.'),
|
||||
('blacklist.txt', '.')
|
||||
('.env', '.')
|
||||
],
|
||||
hiddenimports=[
|
||||
'cursor_auth',
|
||||
|
166
control.py
166
control.py
@ -58,97 +58,7 @@ class BrowserControl:
|
||||
def get_current_tab(self):
|
||||
"""获取当前标签页"""
|
||||
return self.browser
|
||||
|
||||
def generate_new_email(self):
|
||||
"""点击新的按钮生成新邮箱"""
|
||||
try:
|
||||
print(f"{Fore.CYAN}{EMOJI['MAIL']} {self.translator.get('control.generate_email')}...{Style.RESET_ALL}")
|
||||
new_button = self.browser.ele('xpath://button[contains(@class, "egenbut")]')
|
||||
if new_button:
|
||||
new_button.click()
|
||||
time.sleep(1) # 等待生成
|
||||
print(f"{Fore.GREEN}{EMOJI['SUCCESS']} {self.translator.get('control.generate_email_success')}{Style.RESET_ALL}")
|
||||
return True
|
||||
else:
|
||||
print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('control.generate_email_failed')}{Style.RESET_ALL}")
|
||||
return False
|
||||
except Exception as e:
|
||||
print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('control.browser_error', error=str(e))}{Style.RESET_ALL}")
|
||||
return False
|
||||
|
||||
def select_email_domain(self, domain_index=None):
|
||||
"""选择邮箱域名,如果不指定index则随机选择"""
|
||||
try:
|
||||
print(f"{Fore.CYAN}{EMOJI['MAIL']} {self.translator.get('control.select_email_domain')}...{Style.RESET_ALL}")
|
||||
|
||||
# 读取黑名单域名
|
||||
blacklist = []
|
||||
try:
|
||||
with open('blacklist.txt', 'r', encoding='utf-8') as f:
|
||||
blacklist = [line.strip().lower() for line in f if line.strip()]
|
||||
except FileNotFoundError:
|
||||
# 如果文件不存在,创建一个包含已知黑名单域名的文件
|
||||
with open('blacklist.txt', 'w', encoding='utf-8') as f:
|
||||
f.write("fr.nf\nyopmail.com\n1s.fr\nfr.cr")
|
||||
blacklist = ["fr.nf", "yopmail.com", "1s.fr", "fr.cr"]
|
||||
|
||||
# 找到下拉框
|
||||
select_element = self.browser.ele('xpath://select[@id="seldom"]')
|
||||
if select_element:
|
||||
# 获取所有选项
|
||||
all_options = []
|
||||
new_options = self.browser.eles('xpath://select[@id="seldom"]/optgroup[@label="-- 新的 --"]/option')
|
||||
other_options = self.browser.eles('xpath://select[@id="seldom"]/optgroup[@label="-- 其他 --"]/option')
|
||||
all_options.extend(new_options)
|
||||
all_options.extend(other_options)
|
||||
|
||||
if all_options:
|
||||
max_attempts = 5
|
||||
attempt = 0
|
||||
|
||||
while attempt < max_attempts:
|
||||
if domain_index is None:
|
||||
domain_index = random.randint(0, len(all_options) - 1)
|
||||
|
||||
if domain_index < len(all_options):
|
||||
selected_domain = all_options[domain_index].text.lower()
|
||||
|
||||
# 检查域名是否在黑名单中
|
||||
is_blacklisted = False
|
||||
for blocked_domain in blacklist:
|
||||
if blocked_domain in selected_domain:
|
||||
print(f"{Fore.YELLOW}{EMOJI['INFO']} {self.translator.get('control.blocked_domain', domain=blocked_domain)}{Style.RESET_ALL}")
|
||||
domain_index = None
|
||||
attempt += 1
|
||||
is_blacklisted = True
|
||||
break
|
||||
|
||||
if is_blacklisted:
|
||||
continue
|
||||
|
||||
print(f"{Fore.CYAN}{EMOJI['MAIL']} {self.translator.get('control.select_email_domain')}: {selected_domain}{Style.RESET_ALL}")
|
||||
|
||||
# 点击选择
|
||||
all_options[domain_index].click()
|
||||
time.sleep(1)
|
||||
print(f"{Fore.GREEN}{EMOJI['SUCCESS']} {self.translator.get('control.select_email_domain_success')}{Style.RESET_ALL}")
|
||||
return True
|
||||
|
||||
attempt += 1
|
||||
|
||||
print(f"{Fore.RED}{EMOJI['ERROR']} 无法找到可用的域名{Style.RESET_ALL}")
|
||||
return False
|
||||
|
||||
print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('control.no_available_domain_options', count=len(all_options))}{Style.RESET_ALL}")
|
||||
return False
|
||||
else:
|
||||
print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('control.no_domain_select_box')}{Style.RESET_ALL}")
|
||||
return False
|
||||
|
||||
except Exception as e:
|
||||
print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('control.select_email_domain_failed', error=str(e))}{Style.RESET_ALL}")
|
||||
return False
|
||||
|
||||
|
||||
def wait_for_page_load(self, seconds=2):
|
||||
"""等待页面加载"""
|
||||
time.sleep(seconds)
|
||||
@ -164,80 +74,6 @@ class BrowserControl:
|
||||
print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('control.browser_error', error=str(e))}{Style.RESET_ALL}")
|
||||
return False
|
||||
|
||||
def copy_and_get_email(self):
|
||||
"""获取邮箱地址"""
|
||||
try:
|
||||
print(f"{Fore.CYAN}{EMOJI['MAIL']} {self.translator.get('control.generate_email')}...{Style.RESET_ALL}")
|
||||
|
||||
# 等待元素加载
|
||||
time.sleep(1)
|
||||
|
||||
# 获取邮箱名称
|
||||
try:
|
||||
email_div = self.browser.ele('xpath://div[@class="segen"]//div[contains(@style, "color: #e5e5e5")]')
|
||||
if email_div:
|
||||
email_name = email_div.text.split()[0]
|
||||
print(f"{Fore.CYAN}{EMOJI['MAIL']} {self.translator.get('control.get_email_name')}: {email_name}{Style.RESET_ALL}")
|
||||
else:
|
||||
print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('control.get_email_name_failed')}{Style.RESET_ALL}")
|
||||
return None
|
||||
except Exception as e:
|
||||
print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('control.get_email_name_failed', error=str(e))}{Style.RESET_ALL}")
|
||||
return None
|
||||
|
||||
# 直接使用上一步选择的域名
|
||||
try:
|
||||
domain = self.browser.ele('xpath://select[@id="seldom"]').value
|
||||
if not domain: # 如果获取不到value,尝试获取选中的选项文本
|
||||
selected_option = self.browser.ele('xpath://select[@id="seldom"]/option[1]')
|
||||
domain = selected_option.text if selected_option else "@yopmail.com" # 使用默认域名作为后备
|
||||
except:
|
||||
domain = "@yopmail.com" # 如果出错,使用默认域名
|
||||
|
||||
# 组合完整邮箱地址
|
||||
full_email = f"{email_name}{domain}"
|
||||
print(f"{Fore.GREEN}{EMOJI['MAIL']} {self.translator.get('control.get_email_address')}: {full_email}{Style.RESET_ALL}")
|
||||
return full_email
|
||||
|
||||
except Exception as e:
|
||||
print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('control.get_email_address_failed', error=str(e))}{Style.RESET_ALL}")
|
||||
return None
|
||||
|
||||
def view_mailbox(self):
|
||||
"""点击查看邮箱按钮"""
|
||||
try:
|
||||
print(f"{Fore.CYAN}{EMOJI['MAIL']} {self.translator.get('control.enter_mailbox')}...{Style.RESET_ALL}")
|
||||
view_button = self.browser.ele('xpath://button[contains(@class, "egenbut") and contains(.//span, "查看邮箱")]')
|
||||
if view_button:
|
||||
view_button.click()
|
||||
time.sleep(2) # 等待页面加载
|
||||
print(f"{Fore.GREEN}{EMOJI['SUCCESS']} {self.translator.get('control.enter_mailbox_success')}{Style.RESET_ALL}")
|
||||
return True
|
||||
else:
|
||||
print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('control.no_view_mailbox_button')}{Style.RESET_ALL}")
|
||||
return False
|
||||
except Exception as e:
|
||||
print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('control.enter_mailbox_failed', error=str(e))}{Style.RESET_ALL}")
|
||||
return False
|
||||
|
||||
def refresh_mailbox(self):
|
||||
"""刷新邮箱获取最新信息"""
|
||||
try:
|
||||
print(f"{Fore.CYAN}{EMOJI['MAIL']} {self.translator.get('control.refresh_mailbox')}...{Style.RESET_ALL}")
|
||||
refresh_button = self.browser.ele('xpath://button[@id="refresh"]')
|
||||
if refresh_button:
|
||||
refresh_button.click()
|
||||
time.sleep(2) # 等待刷新完成
|
||||
print(f"{Fore.GREEN}{EMOJI['SUCCESS']} {self.translator.get('control.refresh_mailbox_success')}{Style.RESET_ALL}")
|
||||
return True
|
||||
else:
|
||||
print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('control.no_refresh_button')}{Style.RESET_ALL}")
|
||||
return False
|
||||
except Exception as e:
|
||||
print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('control.refresh_mailbox_failed', error=str(e))}{Style.RESET_ALL}")
|
||||
return False
|
||||
|
||||
|
||||
def get_verification_code(self):
|
||||
"""从邮件中获取验证码"""
|
||||
try:
|
||||
|
@ -100,12 +100,11 @@ def setup_driver(translator=None):
|
||||
|
||||
# 使用无痕模式
|
||||
co.set_argument("--incognito")
|
||||
co.set_argument("--headless=new")
|
||||
|
||||
# 设置随机端口
|
||||
co.auto_port()
|
||||
|
||||
# 使用有头模式
|
||||
# 使用有头模式(一定要设置为False,模擬人類操作)
|
||||
co.headless(False)
|
||||
|
||||
try:
|
||||
|
@ -1,22 +0,0 @@
|
||||
{
|
||||
"manifest_version": 3,
|
||||
"name": "Recaptcha Blocker",
|
||||
"version": "1.0",
|
||||
"description": "Blocks reCAPTCHA from loading",
|
||||
"content_scripts": [
|
||||
{
|
||||
"matches": ["*://yopmail.com/zh/wm*"],
|
||||
"js": ["script.js"],
|
||||
"run_at": "document_start",
|
||||
"all_frames": true
|
||||
}
|
||||
],
|
||||
"permissions": [
|
||||
"webNavigation",
|
||||
"activeTab"
|
||||
],
|
||||
"host_permissions": [
|
||||
"*://yopmail.com/*",
|
||||
"*://*.google.com/*"
|
||||
]
|
||||
}
|
@ -1,123 +0,0 @@
|
||||
// Debug logging function
|
||||
function log(message) {
|
||||
console.log(`[reCAPTCHA Bypass] ${new Date().toISOString()}: ${message}`);
|
||||
}
|
||||
|
||||
// Function to get element by selector
|
||||
function qSelector(selector) {
|
||||
return document.querySelector(selector);
|
||||
}
|
||||
|
||||
// Constants
|
||||
const MAX_ATTEMPTS = 1;
|
||||
const SELECTORS = {
|
||||
CHECK_BOX: ".recaptcha-checkbox-border",
|
||||
AUDIO_BUTTON: "#recaptcha-audio-button",
|
||||
PLAY_BUTTON: ".rc-audiochallenge-play-button .rc-button-default",
|
||||
AUDIO_SOURCE: "#audio-source",
|
||||
IMAGE_SELECT: "#rc-imageselect",
|
||||
RESPONSE_FIELD: ".rc-audiochallenge-response-field",
|
||||
AUDIO_ERROR_MESSAGE: ".rc-audiochallenge-error-message",
|
||||
AUDIO_RESPONSE: "#audio-response",
|
||||
RELOAD_BUTTON: "#recaptcha-reload-button",
|
||||
RECAPTCHA_STATUS: "#recaptcha-accessible-status",
|
||||
DOSCAPTCHA: ".rc-doscaptcha-body",
|
||||
VERIFY_BUTTON: "#recaptcha-verify-button"
|
||||
};
|
||||
|
||||
// Function to check if element is hidden
|
||||
function isHidden(el) {
|
||||
return (el.offsetParent === null);
|
||||
}
|
||||
|
||||
// Function to handle the bypass process
|
||||
async function bypassRecaptcha() {
|
||||
try {
|
||||
log('Starting bypass process...');
|
||||
log('Waiting 3 seconds before starting...');
|
||||
await new Promise(resolve => setTimeout(resolve, 3000));
|
||||
|
||||
let solved = false;
|
||||
let checkBoxClicked = false;
|
||||
let requestCount = 0;
|
||||
|
||||
const recaptchaInitialStatus = qSelector(SELECTORS.RECAPTCHA_STATUS) ?
|
||||
qSelector(SELECTORS.RECAPTCHA_STATUS).innerText : "";
|
||||
|
||||
log('Initial reCAPTCHA status: ' + recaptchaInitialStatus);
|
||||
|
||||
// Main bypass logic
|
||||
try {
|
||||
if (!checkBoxClicked && qSelector(SELECTORS.CHECK_BOX) &&
|
||||
!isHidden(qSelector(SELECTORS.CHECK_BOX))) {
|
||||
log('Clicking checkbox...');
|
||||
qSelector(SELECTORS.CHECK_BOX).click();
|
||||
checkBoxClicked = true;
|
||||
}
|
||||
|
||||
// Check if the captcha is solved
|
||||
if (qSelector(SELECTORS.RECAPTCHA_STATUS) &&
|
||||
(qSelector(SELECTORS.RECAPTCHA_STATUS).innerText != recaptchaInitialStatus)) {
|
||||
solved = true;
|
||||
log('SOLVED!');
|
||||
}
|
||||
|
||||
if (requestCount > MAX_ATTEMPTS) {
|
||||
log('Attempted Max Retries. Stopping the solver');
|
||||
solved = true;
|
||||
}
|
||||
|
||||
// Stop solving when Automated queries message is shown
|
||||
if (qSelector(SELECTORS.DOSCAPTCHA) &&
|
||||
qSelector(SELECTORS.DOSCAPTCHA).innerText.length > 0) {
|
||||
log('Automated Queries Detected');
|
||||
}
|
||||
|
||||
} catch (err) {
|
||||
log(`Error in main bypass logic: ${err.message}`);
|
||||
}
|
||||
|
||||
log('Bypass process completed');
|
||||
|
||||
// If not solved, retry after delay
|
||||
if (!solved && requestCount < MAX_ATTEMPTS) {
|
||||
requestCount++;
|
||||
log(`Retrying... Attempt ${requestCount} of ${MAX_ATTEMPTS}`);
|
||||
setTimeout(bypassRecaptcha, 2000);
|
||||
}
|
||||
|
||||
} catch (e) {
|
||||
log(`Bypass failed: ${e.message}`);
|
||||
}
|
||||
}
|
||||
|
||||
// Create a MutationObserver to watch for reCAPTCHA elements
|
||||
log('Setting up MutationObserver...');
|
||||
const observer = new MutationObserver((mutations) => {
|
||||
mutations.forEach((mutation) => {
|
||||
mutation.addedNodes.forEach((node) => {
|
||||
if (node.nodeType === 1 && // Element node
|
||||
((node.tagName === 'SCRIPT' && node.src && node.src.includes('recaptcha')) ||
|
||||
(node.tagName === 'IFRAME' && node.src && node.src.includes('recaptcha')))) {
|
||||
log(`Detected new reCAPTCHA element: ${node.tagName} - ${node.src}`);
|
||||
bypassRecaptcha();
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
// Start observing
|
||||
observer.observe(document, {
|
||||
childList: true,
|
||||
subtree: true
|
||||
});
|
||||
log('MutationObserver started');
|
||||
|
||||
// Run on page load
|
||||
if (document.readyState === 'loading') {
|
||||
log('Document still loading, waiting for DOMContentLoaded');
|
||||
document.addEventListener('DOMContentLoaded', bypassRecaptcha);
|
||||
} else {
|
||||
log('Document already loaded, starting bypass process');
|
||||
bypassRecaptcha();
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user