This commit is contained in:
cnlimiter
2026-03-14 16:51:57 +08:00
parent dc1334fbab
commit 9d3099fcd8
35 changed files with 9490 additions and 0 deletions

34
src/config/__init__.py Normal file
View File

@@ -0,0 +1,34 @@
"""
配置模块
"""
from .settings import Settings, get_settings, update_settings, get_database_url
from .constants import (
AccountStatus,
TaskStatus,
EmailServiceType,
APP_NAME,
APP_VERSION,
OTP_CODE_PATTERN,
DEFAULT_PASSWORD_LENGTH,
PASSWORD_CHARSET,
DEFAULT_USER_INFO,
OPENAI_API_ENDPOINTS,
)
__all__ = [
'Settings',
'get_settings',
'update_settings',
'get_database_url',
'AccountStatus',
'TaskStatus',
'EmailServiceType',
'APP_NAME',
'APP_VERSION',
'OTP_CODE_PATTERN',
'DEFAULT_PASSWORD_LENGTH',
'PASSWORD_CHARSET',
'DEFAULT_USER_INFO',
'OPENAI_API_ENDPOINTS',
]

265
src/config/constants.py Normal file
View File

@@ -0,0 +1,265 @@
"""
常量定义
"""
from enum import Enum
from typing import Dict, List, Tuple
# ============================================================================
# 枚举类型
# ============================================================================
class AccountStatus(str, Enum):
"""账户状态"""
ACTIVE = "active"
EXPIRED = "expired"
BANNED = "banned"
FAILED = "failed"
class TaskStatus(str, Enum):
"""任务状态"""
PENDING = "pending"
RUNNING = "running"
COMPLETED = "completed"
FAILED = "failed"
CANCELLED = "cancelled"
class EmailServiceType(str, Enum):
"""邮箱服务类型"""
TEMPMAIL = "tempmail"
OUTLOOK = "outlook"
CUSTOM_DOMAIN = "custom_domain"
# ============================================================================
# 应用常量
# ============================================================================
APP_NAME = "OpenAI/Codex CLI 自动注册系统"
APP_VERSION = "2.0.0"
APP_DESCRIPTION = "自动注册 OpenAI/Codex CLI 账号的系统"
# ============================================================================
# OpenAI OAuth 相关常量
# ============================================================================
# OAuth 参数
OAUTH_CLIENT_ID = "app_EMoamEEZ73f0CkXaXp7hrann"
OAUTH_AUTH_URL = "https://auth.openai.com/oauth/authorize"
OAUTH_TOKEN_URL = "https://auth.openai.com/oauth/token"
OAUTH_REDIRECT_URI = "http://localhost:1455/auth/callback"
OAUTH_SCOPE = "openid email profile offline_access"
# OpenAI API 端点
OPENAI_API_ENDPOINTS = {
"sentinel": "https://sentinel.openai.com/backend-api/sentinel/req",
"signup": "https://auth.openai.com/api/accounts/authorize/continue",
"register": "https://auth.openai.com/api/accounts/user/register",
"send_otp": "https://auth.openai.com/api/accounts/email-otp/send",
"validate_otp": "https://auth.openai.com/api/accounts/email-otp/validate",
"create_account": "https://auth.openai.com/api/accounts/create_account",
"select_workspace": "https://auth.openai.com/api/accounts/workspace/select",
}
# ============================================================================
# 邮箱服务相关常量
# ============================================================================
# Tempmail.lol API 端点
TEMPMAIL_API_ENDPOINTS = {
"create_inbox": "/inbox/create",
"get_inbox": "/inbox",
}
# 自定义域名邮箱 API 端点
CUSTOM_DOMAIN_API_ENDPOINTS = {
"get_config": "/api/config",
"create_email": "/api/emails/generate",
"list_emails": "/api/emails",
"get_email_messages": "/api/emails/{emailId}",
"delete_email": "/api/emails/{emailId}",
"get_message": "/api/emails/{emailId}/{messageId}",
}
# 邮箱服务默认配置
EMAIL_SERVICE_DEFAULTS = {
"tempmail": {
"base_url": "https://api.tempmail.lol/v2",
"timeout": 30,
"max_retries": 3,
},
"outlook": {
"imap_server": "outlook.office365.com",
"imap_port": 993,
"smtp_server": "smtp.office365.com",
"smtp_port": 587,
"timeout": 30,
},
"custom_domain": {
"base_url": "", # 需要用户配置
"api_key_header": "X-API-Key",
"timeout": 30,
"max_retries": 3,
}
}
# ============================================================================
# 注册流程相关常量
# ============================================================================
# 验证码相关
OTP_CODE_PATTERN = r"(?<!\d)(\d{6})(?!\d)"
OTP_WAIT_TIMEOUT = 120 # 秒
OTP_POLL_INTERVAL = 3 # 秒
OTP_MAX_ATTEMPTS = 40 # 最大轮询次数
# 密码生成
PASSWORD_CHARSET = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
DEFAULT_PASSWORD_LENGTH = 12
# 用户信息(用于注册)
DEFAULT_USER_INFO = {
"name": "Neo",
"birthdate": "2000-02-20",
}
# ============================================================================
# 代理相关常量
# ============================================================================
PROXY_TYPES = ["http", "socks5", "socks5h"]
DEFAULT_PROXY_CONFIG = {
"enabled": False,
"type": "http",
"host": "127.0.0.1",
"port": 7890,
}
# ============================================================================
# 数据库相关常量
# ============================================================================
# 数据库表名
DB_TABLE_NAMES = {
"accounts": "accounts",
"email_services": "email_services",
"registration_tasks": "registration_tasks",
"settings": "settings",
}
# 默认设置
DEFAULT_SETTINGS = [
# (key, value, description, category)
("system.name", APP_NAME, "系统名称", "general"),
("system.version", APP_VERSION, "系统版本", "general"),
("logs.retention_days", "30", "日志保留天数", "general"),
("openai.client_id", OAUTH_CLIENT_ID, "OpenAI OAuth Client ID", "openai"),
("openai.auth_url", OAUTH_AUTH_URL, "OpenAI 认证地址", "openai"),
("openai.token_url", OAUTH_TOKEN_URL, "OpenAI Token 地址", "openai"),
("openai.redirect_uri", OAUTH_REDIRECT_URI, "OpenAI 回调地址", "openai"),
("openai.scope", OAUTH_SCOPE, "OpenAI 权限范围", "openai"),
("proxy.enabled", "false", "是否启用代理", "proxy"),
("proxy.type", "http", "代理类型 (http/socks5)", "proxy"),
("proxy.host", "127.0.0.1", "代理主机", "proxy"),
("proxy.port", "7890", "代理端口", "proxy"),
("registration.max_retries", "3", "最大重试次数", "registration"),
("registration.timeout", "120", "超时时间(秒)", "registration"),
("registration.default_password_length", "12", "默认密码长度", "registration"),
("webui.host", "0.0.0.0", "Web UI 监听主机", "webui"),
("webui.port", "8000", "Web UI 监听端口", "webui"),
("webui.debug", "true", "调试模式", "webui"),
]
# ============================================================================
# Web UI 相关常量
# ============================================================================
# WebSocket 事件
WEBSOCKET_EVENTS = {
"CONNECT": "connect",
"DISCONNECT": "disconnect",
"LOG": "log",
"STATUS": "status",
"ERROR": "error",
"COMPLETE": "complete",
}
# API 响应状态码
API_STATUS_CODES = {
"SUCCESS": 200,
"CREATED": 201,
"BAD_REQUEST": 400,
"UNAUTHORIZED": 401,
"FORBIDDEN": 403,
"NOT_FOUND": 404,
"CONFLICT": 409,
"INTERNAL_ERROR": 500,
}
# 分页
DEFAULT_PAGE_SIZE = 20
MAX_PAGE_SIZE = 100
# ============================================================================
# 错误消息
# ============================================================================
ERROR_MESSAGES = {
# 通用错误
"DATABASE_ERROR": "数据库操作失败",
"CONFIG_ERROR": "配置错误",
"NETWORK_ERROR": "网络连接失败",
"TIMEOUT": "操作超时",
"VALIDATION_ERROR": "参数验证失败",
# 邮箱服务错误
"EMAIL_SERVICE_UNAVAILABLE": "邮箱服务不可用",
"EMAIL_CREATION_FAILED": "创建邮箱失败",
"OTP_NOT_RECEIVED": "未收到验证码",
"OTP_INVALID": "验证码无效",
# OpenAI 相关错误
"OPENAI_AUTH_FAILED": "OpenAI 认证失败",
"OPENAI_RATE_LIMIT": "OpenAI 接口限流",
"OPENAI_CAPTCHA": "遇到验证码",
# 代理错误
"PROXY_FAILED": "代理连接失败",
"PROXY_AUTH_FAILED": "代理认证失败",
# 账户错误
"ACCOUNT_NOT_FOUND": "账户不存在",
"ACCOUNT_ALREADY_EXISTS": "账户已存在",
"ACCOUNT_INVALID": "账户无效",
# 任务错误
"TASK_NOT_FOUND": "任务不存在",
"TASK_ALREADY_RUNNING": "任务已在运行中",
"TASK_CANCELLED": "任务已取消",
}
# ============================================================================
# 正则表达式
# ============================================================================
REGEX_PATTERNS = {
"EMAIL": r"^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$",
"URL": r"https?://(?:[-\w.]|(?:%[\da-fA-F]{2}))+",
"IP_ADDRESS": r"\b(?:\d{1,3}\.){3}\d{1,3}\b",
"OTP_CODE": OTP_CODE_PATTERN,
}
# ============================================================================
# 时间常量
# ============================================================================
TIME_CONSTANTS = {
"SECOND": 1,
"MINUTE": 60,
"HOUR": 3600,
"DAY": 86400,
"WEEK": 604800,
}

168
src/config/settings.py Normal file
View File

@@ -0,0 +1,168 @@
"""
配置管理 - Pydantic 设置模型
"""
import os
from typing import Optional, Dict, Any
from pydantic import Field, field_validator
from pydantic.types import SecretStr
from pydantic_settings import BaseSettings, SettingsConfigDict
class Settings(BaseSettings):
"""
应用配置
优先级:环境变量 > .env 文件 > 默认值
"""
model_config = SettingsConfigDict(
env_file=".env",
env_file_encoding="utf-8",
case_sensitive=False,
extra="ignore",
)
# 应用信息
app_name: str = Field(default="OpenAI/Codex CLI 自动注册系统")
app_version: str = Field(default="2.0.0")
debug: bool = Field(default=False)
# 数据库配置
database_url: str = Field(
default=os.path.join(
os.path.dirname(os.path.dirname(os.path.dirname(__file__))),
'data',
'database.db'
)
)
@field_validator('database_url', mode='before')
@classmethod
def validate_database_url(cls, v):
if isinstance(v, str) and v.startswith("sqlite:///"):
return v
if isinstance(v, str) and not v.startswith(("sqlite:///", "postgresql://", "mysql://")):
# 如果是文件路径,转换为 SQLite URL
if os.path.isabs(v) or ":/" not in v:
return f"sqlite:///{v}"
return v
# Web UI 配置
webui_host: str = Field(default="0.0.0.0")
webui_port: int = Field(default=8000)
webui_secret_key: SecretStr = Field(
default=SecretStr("your-secret-key-change-in-production")
)
# 日志配置
log_level: str = Field(default="INFO")
log_file: str = Field(default="logs/app.log")
log_retention_days: int = Field(default=30)
# OpenAI 配置
openai_client_id: str = Field(default="app_EMoamEEZ73f0CkXaXp7hrann")
openai_auth_url: str = Field(default="https://auth.openai.com/oauth/authorize")
openai_token_url: str = Field(default="https://auth.openai.com/oauth/token")
openai_redirect_uri: str = Field(default="http://localhost:1455/auth/callback")
openai_scope: str = Field(default="openid email profile offline_access")
# 代理配置
proxy_enabled: bool = Field(default=False)
proxy_type: str = Field(default="http") # http, socks5
proxy_host: str = Field(default="127.0.0.1")
proxy_port: int = Field(default=7890)
proxy_username: Optional[str] = Field(default=None)
proxy_password: Optional[SecretStr] = Field(default=None)
@property
def proxy_url(self) -> Optional[str]:
"""获取完整的代理 URL"""
if not self.proxy_enabled:
return None
if self.proxy_type == "http":
scheme = "http"
elif self.proxy_type == "socks5":
scheme = "socks5"
else:
return None
auth = ""
if self.proxy_username and self.proxy_password:
auth = f"{self.proxy_username}:{self.proxy_password.get_secret_value()}@"
return f"{scheme}://{auth}{self.proxy_host}:{self.proxy_port}"
# 注册配置
registration_max_retries: int = Field(default=3)
registration_timeout: int = Field(default=120) # 秒
registration_default_password_length: int = Field(default=12)
registration_sleep_min: int = Field(default=5)
registration_sleep_max: int = Field(default=30)
# 邮箱服务配置
email_service_priority: Dict[str, int] = Field(
default={"tempmail": 0, "outlook": 1, "custom_domain": 2}
)
# Tempmail.lol 配置
tempmail_base_url: str = Field(default="https://api.tempmail.lol/v2")
tempmail_timeout: int = Field(default=30)
tempmail_max_retries: int = Field(default=3)
# 自定义域名邮箱配置
custom_domain_base_url: str = Field(default="")
custom_domain_api_key: Optional[SecretStr] = Field(default=None)
# 安全配置
encryption_key: SecretStr = Field(
default=SecretStr("your-encryption-key-change-in-production")
)
# 全局配置实例
_settings: Optional[Settings] = None
def get_settings() -> Settings:
"""
获取全局配置实例(单例模式)
"""
global _settings
if _settings is None:
_settings = Settings()
return _settings
def update_settings(**kwargs) -> Settings:
"""
更新配置(用于测试或运行时配置更改)
"""
global _settings
if _settings is None:
_settings = Settings()
# 创建新的配置实例
updated_data = _settings.model_dump()
updated_data.update(kwargs)
_settings = Settings(**updated_data)
return _settings
def get_database_url() -> str:
"""
获取数据库 URL处理相对路径
"""
settings = get_settings()
url = settings.database_url
# 如果 URL 是相对路径,转换为绝对路径
if url.startswith("sqlite:///"):
path = url[10:] # 移除 "sqlite:///"
if not os.path.isabs(path):
# 转换为相对于项目根目录的路径
project_root = os.path.dirname(os.path.dirname(os.path.dirname(__file__)))
abs_path = os.path.join(project_root, path)
return f"sqlite:///{abs_path}"
return url