mirror of
https://github.com/cnlimiter/codex-register.git
synced 2026-05-10 17:42:51 +08:00
feat(settings): 添加验证码配置页面和数据库存储支持
This commit is contained in:
@@ -110,10 +110,6 @@ class Settings(BaseSettings):
|
||||
tempmail_timeout: int = Field(default=30)
|
||||
tempmail_max_retries: int = Field(default=3)
|
||||
|
||||
# 验证码等待配置
|
||||
email_code_timeout: int = Field(default=120) # 验证码等待超时(秒)
|
||||
email_code_poll_interval: int = Field(default=3) # 验证码轮询间隔(秒)
|
||||
|
||||
# 自定义域名邮箱配置
|
||||
custom_domain_base_url: str = Field(default="")
|
||||
custom_domain_api_key: Optional[SecretStr] = Field(default=None)
|
||||
|
||||
@@ -27,8 +27,35 @@ from ..config.constants import (
|
||||
OTP_CODE_SEMANTIC_PATTERN,
|
||||
OPENAI_EMAIL_SENDERS,
|
||||
OPENAI_VERIFICATION_KEYWORDS,
|
||||
OTP_WAIT_TIMEOUT,
|
||||
OTP_POLL_INTERVAL,
|
||||
)
|
||||
from ..config import get_settings
|
||||
from ..database import crud
|
||||
from ..database.session import get_db
|
||||
|
||||
|
||||
def get_email_code_settings() -> dict:
|
||||
"""
|
||||
从数据库获取验证码等待配置
|
||||
|
||||
Returns:
|
||||
dict: 包含 timeout 和 poll_interval 的字典
|
||||
"""
|
||||
try:
|
||||
with get_db() as db:
|
||||
timeout_setting = crud.get_setting(db, "email_code.timeout")
|
||||
poll_interval_setting = crud.get_setting(db, "email_code.poll_interval")
|
||||
|
||||
return {
|
||||
"timeout": int(timeout_setting.value) if timeout_setting else OTP_WAIT_TIMEOUT,
|
||||
"poll_interval": int(poll_interval_setting.value) if poll_interval_setting else OTP_POLL_INTERVAL,
|
||||
}
|
||||
except Exception as e:
|
||||
logger.warning(f"获取验证码配置失败,使用默认值: {e}")
|
||||
return {
|
||||
"timeout": OTP_WAIT_TIMEOUT,
|
||||
"poll_interval": OTP_POLL_INTERVAL,
|
||||
}
|
||||
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
@@ -474,10 +501,10 @@ class OutlookService(BaseEmailService):
|
||||
self.update_status(False, EmailServiceError(f"未找到邮箱对应的账户: {email}"))
|
||||
return None
|
||||
|
||||
# 使用配置的超时时间
|
||||
settings = get_settings()
|
||||
actual_timeout = timeout or settings.email_code_timeout
|
||||
poll_interval = settings.email_code_poll_interval
|
||||
# 从数据库获取验证码等待配置
|
||||
code_settings = get_email_code_settings()
|
||||
actual_timeout = timeout or code_settings["timeout"]
|
||||
poll_interval = code_settings["poll_interval"]
|
||||
|
||||
logger.info(f"[{email}] 开始获取验证码,超时 {actual_timeout}s,OTP发送时间: {otp_sent_at}")
|
||||
|
||||
|
||||
@@ -11,6 +11,7 @@ from pydantic import BaseModel
|
||||
from ...database import crud
|
||||
from ...database.session import get_db
|
||||
from ...config.settings import get_settings, update_settings
|
||||
from ...config.constants import OTP_WAIT_TIMEOUT, OTP_POLL_INTERVAL
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
router = APIRouter()
|
||||
@@ -71,6 +72,11 @@ async def get_all_settings():
|
||||
"""获取所有设置"""
|
||||
settings = get_settings()
|
||||
|
||||
# 从数据库获取验证码设置
|
||||
with get_db() as db:
|
||||
timeout_setting = crud.get_setting(db, "email_code.timeout")
|
||||
poll_interval_setting = crud.get_setting(db, "email_code.poll_interval")
|
||||
|
||||
return {
|
||||
"proxy": {
|
||||
"enabled": settings.proxy_enabled,
|
||||
@@ -97,6 +103,10 @@ async def get_all_settings():
|
||||
"timeout": settings.tempmail_timeout,
|
||||
"max_retries": settings.tempmail_max_retries,
|
||||
},
|
||||
"email_code": {
|
||||
"timeout": int(timeout_setting.value) if timeout_setting else OTP_WAIT_TIMEOUT,
|
||||
"poll_interval": int(poll_interval_setting.value) if poll_interval_setting else OTP_POLL_INTERVAL,
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
@@ -362,6 +372,12 @@ class TempmailSettings(BaseModel):
|
||||
enabled: bool = True
|
||||
|
||||
|
||||
class EmailCodeSettings(BaseModel):
|
||||
"""验证码等待设置"""
|
||||
timeout: int = 120 # 验证码等待超时(秒)
|
||||
poll_interval: int = 3 # 验证码轮询间隔(秒)
|
||||
|
||||
|
||||
@router.get("/tempmail")
|
||||
async def get_tempmail_settings():
|
||||
"""获取临时邮箱设置"""
|
||||
@@ -388,6 +404,49 @@ async def update_tempmail_settings(request: TempmailSettings):
|
||||
return {"success": True, "message": "临时邮箱设置已更新"}
|
||||
|
||||
|
||||
# ============== 验证码等待设置 ==============
|
||||
|
||||
@router.get("/email-code")
|
||||
async def get_email_code_settings():
|
||||
"""获取验证码等待设置"""
|
||||
with get_db() as db:
|
||||
timeout_setting = crud.get_setting(db, "email_code.timeout")
|
||||
poll_interval_setting = crud.get_setting(db, "email_code.poll_interval")
|
||||
|
||||
return {
|
||||
"timeout": int(timeout_setting.value) if timeout_setting else OTP_WAIT_TIMEOUT,
|
||||
"poll_interval": int(poll_interval_setting.value) if poll_interval_setting else OTP_POLL_INTERVAL,
|
||||
}
|
||||
|
||||
|
||||
@router.post("/email-code")
|
||||
async def update_email_code_settings(request: EmailCodeSettings):
|
||||
"""更新验证码等待设置"""
|
||||
with get_db() as db:
|
||||
# 验证参数范围
|
||||
if request.timeout < 30 or request.timeout > 600:
|
||||
raise HTTPException(status_code=400, detail="超时时间必须在 30-600 秒之间")
|
||||
if request.poll_interval < 1 or request.poll_interval > 30:
|
||||
raise HTTPException(status_code=400, detail="轮询间隔必须在 1-30 秒之间")
|
||||
|
||||
crud.set_setting(
|
||||
db,
|
||||
"email_code.timeout",
|
||||
str(request.timeout),
|
||||
description="验证码等待超时(秒)",
|
||||
category="email"
|
||||
)
|
||||
crud.set_setting(
|
||||
db,
|
||||
"email_code.poll_interval",
|
||||
str(request.poll_interval),
|
||||
description="验证码轮询间隔(秒)",
|
||||
category="email"
|
||||
)
|
||||
|
||||
return {"success": True, "message": "验证码等待设置已更新"}
|
||||
|
||||
|
||||
# ============== 代理列表 CRUD ==============
|
||||
|
||||
class ProxyCreateRequest(BaseModel):
|
||||
|
||||
@@ -40,7 +40,9 @@ const elements = {
|
||||
proxyModalTitle: document.getElementById('proxy-modal-title'),
|
||||
// CPA 设置
|
||||
cpaForm: document.getElementById('cpa-form'),
|
||||
testCpaBtn: document.getElementById('test-cpa-btn')
|
||||
testCpaBtn: document.getElementById('test-cpa-btn'),
|
||||
// 验证码设置
|
||||
emailCodeForm: document.getElementById('email-code-form')
|
||||
};
|
||||
|
||||
// 选中的服务 ID
|
||||
@@ -206,6 +208,11 @@ function initEventListeners() {
|
||||
if (elements.testCpaBtn) {
|
||||
elements.testCpaBtn.addEventListener('click', handleTestCpa);
|
||||
}
|
||||
|
||||
// 验证码设置
|
||||
if (elements.emailCodeForm) {
|
||||
elements.emailCodeForm.addEventListener('submit', handleSaveEmailCode);
|
||||
}
|
||||
}
|
||||
|
||||
// 加载设置
|
||||
@@ -227,6 +234,12 @@ async function loadSettings() {
|
||||
document.getElementById('sleep-min').value = data.registration?.sleep_min || 5;
|
||||
document.getElementById('sleep-max').value = data.registration?.sleep_max || 30;
|
||||
|
||||
// 验证码等待配置
|
||||
if (data.email_code) {
|
||||
document.getElementById('email-code-timeout').value = data.email_code.timeout || 120;
|
||||
document.getElementById('email-code-poll-interval').value = data.email_code.poll_interval || 3;
|
||||
}
|
||||
|
||||
// 加载 CPA 设置
|
||||
loadCpaSettings();
|
||||
|
||||
@@ -399,6 +412,36 @@ async function handleSaveRegistration(e) {
|
||||
}
|
||||
}
|
||||
|
||||
// 保存验证码等待配置
|
||||
async function handleSaveEmailCode(e) {
|
||||
e.preventDefault();
|
||||
|
||||
const timeout = parseInt(document.getElementById('email-code-timeout').value);
|
||||
const pollInterval = parseInt(document.getElementById('email-code-poll-interval').value);
|
||||
|
||||
// 客户端验证
|
||||
if (timeout < 30 || timeout > 600) {
|
||||
toast.error('等待超时必须在 30-600 秒之间');
|
||||
return;
|
||||
}
|
||||
if (pollInterval < 1 || pollInterval > 30) {
|
||||
toast.error('轮询间隔必须在 1-30 秒之间');
|
||||
return;
|
||||
}
|
||||
|
||||
const data = {
|
||||
timeout: timeout,
|
||||
poll_interval: pollInterval
|
||||
};
|
||||
|
||||
try {
|
||||
await api.post('/settings/email-code', data);
|
||||
toast.success('验证码配置已保存');
|
||||
} catch (error) {
|
||||
toast.error('保存失败: ' + error.message);
|
||||
}
|
||||
}
|
||||
|
||||
// 备份数据库
|
||||
async function handleBackup() {
|
||||
elements.backupBtn.disabled = true;
|
||||
|
||||
@@ -37,6 +37,7 @@
|
||||
<button class="tab-btn active" data-tab="proxy">🌐 代理设置</button>
|
||||
<button class="tab-btn" data-tab="cpa">☁️ CPA上传</button>
|
||||
<button class="tab-btn" data-tab="registration">⚙️ 注册配置</button>
|
||||
<button class="tab-btn" data-tab="email-code">📧 验证码配置</button>
|
||||
<button class="tab-btn" data-tab="database">💾 数据库</button>
|
||||
</div>
|
||||
|
||||
@@ -270,6 +271,52 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 验证码配置 -->
|
||||
<div class="tab-content" id="email-code-tab">
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<h3>验证码等待配置</h3>
|
||||
<span class="hint">配置 Outlook 邮箱验证码获取的超时时间和轮询间隔</span>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<form id="email-code-form">
|
||||
<div class="form-row">
|
||||
<div class="form-group">
|
||||
<label for="email-code-timeout">等待超时 (秒)</label>
|
||||
<input type="number" id="email-code-timeout" name="timeout" value="120" min="30" max="600">
|
||||
<span class="hint">等待验证码的最大时间,建议 60-300 秒</span>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="email-code-poll-interval">轮询间隔 (秒)</label>
|
||||
<input type="number" id="email-code-poll-interval" name="poll_interval" value="3" min="1" max="30">
|
||||
<span class="hint">检查邮箱的时间间隔,建议 2-5 秒</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-actions">
|
||||
<button type="submit" class="btn btn-primary">💾 保存设置</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card" style="margin-top: var(--spacing-lg);">
|
||||
<div class="card-header">
|
||||
<h3>验证码获取策略</h3>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<ul class="info-list">
|
||||
<li><strong>渐进式检查</strong>:前 3 次轮询只检查未读邮件,之后检查所有邮件</li>
|
||||
<li><strong>时间戳过滤</strong>:自动跳过 OTP 发送前的旧邮件</li>
|
||||
<li><strong>验证码去重</strong>:避免重复使用同一验证码</li>
|
||||
<li><strong>多策略提取</strong>:主题优先 → 语义匹配 → 兜底匹配</li>
|
||||
<li><strong>发件人验证</strong>:严格验证邮件来自 OpenAI 官方</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 数据库 -->
|
||||
<div class="tab-content" id="database-tab">
|
||||
<div class="card">
|
||||
|
||||
Reference in New Issue
Block a user