feat(s2a_service): Add pure API authorization mode without browser
- Add S2A_API_MODE configuration option to enable browser-less authorization - Implement S2AApiAuthorizer class using curl_cffi for browser fingerprint simulation - Add Sentinel PoW (Proof of Work) solver with FNV-1a hashing algorithm - Implement OAuth flow via direct API calls instead of browser automation - Add s2a_api_authorize() function to handle email/password authentication - Support proxy configuration for API requests - Add requirements token generation for API authentication - Update browser_automation.py to check S2A_API_MODE and route to API or browser flow - Update config.py to load S2A_API_MODE from configuration - Add api_mode option to config.toml.example with documentation - Improves performance and stability by eliminating browser overhead while maintaining compatibility with existing browser-based flow
This commit is contained in:
@@ -48,6 +48,7 @@ from config import (
|
||||
S2A_GROUP_NAMES,
|
||||
S2A_GROUP_IDS,
|
||||
S2A_ADMIN_KEY,
|
||||
S2A_API_MODE,
|
||||
BROWSER_RANDOM_FINGERPRINT,
|
||||
batch_remove_teams_by_names,
|
||||
)
|
||||
@@ -55,7 +56,8 @@ from utils import load_team_tracker, get_all_incomplete_accounts, save_team_trac
|
||||
from bot_notifier import BotNotifier, set_notifier, progress_finish
|
||||
from s2a_service import (
|
||||
s2a_get_dashboard_stats, format_dashboard_stats, s2a_get_keys_with_usage, format_keys_usage,
|
||||
s2a_get_error_accounts, s2a_delete_account, s2a_batch_delete_error_accounts
|
||||
s2a_get_error_accounts, s2a_delete_account, s2a_batch_delete_error_accounts,
|
||||
s2a_api_authorize_single, s2a_batch_api_authorize
|
||||
)
|
||||
from email_service import gptmail_service, unified_create_email
|
||||
from logger import log
|
||||
@@ -159,6 +161,7 @@ class ProvisionerBot:
|
||||
("include_owners", self.cmd_include_owners),
|
||||
("reload", self.cmd_reload),
|
||||
("s2a_config", self.cmd_s2a_config),
|
||||
("api_auth", self.cmd_api_auth),
|
||||
("clean", self.cmd_clean),
|
||||
("clean_errors", self.cmd_clean_errors),
|
||||
("clean_teams", self.cmd_clean_teams),
|
||||
@@ -287,6 +290,7 @@ class ProvisionerBot:
|
||||
BotCommand("keys_usage", "查看 API 密钥用量"),
|
||||
BotCommand("stock", "查看账号库存"),
|
||||
BotCommand("s2a_config", "配置 S2A 参数"),
|
||||
BotCommand("api_auth", "API 模式授权账号"),
|
||||
BotCommand("import", "导入账号到 team.json"),
|
||||
BotCommand("verify", "验证未验证的账号"),
|
||||
BotCommand("verify_all", "强制重新验证所有账号"),
|
||||
@@ -355,6 +359,7 @@ class ProvisionerBot:
|
||||
/keys_usage - 查看 API 密钥用量
|
||||
/stock - 查看账号库存
|
||||
/s2a_config - 配置 S2A 参数
|
||||
/api_auth - API 模式授权 (无需浏览器)
|
||||
/clean_errors - 清理错误状态账号
|
||||
|
||||
<b>🧹 清理管理:</b>
|
||||
@@ -1072,6 +1077,92 @@ class ProvisionerBot:
|
||||
except Exception as e:
|
||||
await update.message.reply_text(f"❌ 修改配置失败: {e}")
|
||||
|
||||
@admin_only
|
||||
async def cmd_api_auth(self, update: Update, context: ContextTypes.DEFAULT_TYPE):
|
||||
"""使用纯 API 模式授权账号到 S2A (无需浏览器)
|
||||
|
||||
用法:
|
||||
/api_auth email password - 授权单个账号
|
||||
/api_auth - 显示帮助信息
|
||||
"""
|
||||
if AUTH_PROVIDER != "s2a":
|
||||
await update.message.reply_text(
|
||||
"❌ 此命令仅在 S2A 模式下可用\n"
|
||||
"当前授权服务: " + AUTH_PROVIDER
|
||||
)
|
||||
return
|
||||
|
||||
# 无参数时显示帮助
|
||||
if not context.args:
|
||||
api_mode_status = "✅ 已启用" if S2A_API_MODE else "❌ 未启用"
|
||||
lines = [
|
||||
"<b>🔐 S2A API 授权</b>",
|
||||
"",
|
||||
f"<b>API 模式:</b> {api_mode_status}",
|
||||
"",
|
||||
"<b>用法:</b>",
|
||||
"<code>/api_auth email password</code>",
|
||||
"",
|
||||
"<b>示例:</b>",
|
||||
"<code>/api_auth test@example.com MyPassword123</code>",
|
||||
"",
|
||||
"<b>说明:</b>",
|
||||
"• 使用纯 API 方式完成 OAuth 授权",
|
||||
"• 无需浏览器,更快更稳定",
|
||||
"• 需要安装 curl_cffi: <code>pip install curl_cffi</code>",
|
||||
"",
|
||||
"<b>💡 提示:</b>",
|
||||
"• 在 config.toml 中设置 <code>s2a.api_mode = true</code>",
|
||||
"• 可让所有 S2A 授权自动使用 API 模式",
|
||||
]
|
||||
await update.message.reply_text("\n".join(lines), parse_mode="HTML")
|
||||
return
|
||||
|
||||
# 解析参数
|
||||
if len(context.args) < 2:
|
||||
await update.message.reply_text(
|
||||
"❌ 参数不足\n"
|
||||
"用法: /api_auth <email> <password>"
|
||||
)
|
||||
return
|
||||
|
||||
email = context.args[0]
|
||||
password = " ".join(context.args[1:]) # 密码可能包含空格
|
||||
|
||||
# 发送处理中消息
|
||||
msg = await update.message.reply_text(
|
||||
f"🔄 正在授权: <code>{email}</code>\n"
|
||||
"请稍候...",
|
||||
parse_mode="HTML"
|
||||
)
|
||||
|
||||
try:
|
||||
# 执行 API 授权
|
||||
success, message = s2a_api_authorize_single(email, password)
|
||||
|
||||
if success:
|
||||
await msg.edit_text(
|
||||
f"✅ <b>授权成功</b>\n\n"
|
||||
f"📧 邮箱: <code>{email}</code>\n"
|
||||
f"📝 {message}",
|
||||
parse_mode="HTML"
|
||||
)
|
||||
else:
|
||||
await msg.edit_text(
|
||||
f"❌ <b>授权失败</b>\n\n"
|
||||
f"📧 邮箱: <code>{email}</code>\n"
|
||||
f"📝 {message}",
|
||||
parse_mode="HTML"
|
||||
)
|
||||
|
||||
except Exception as e:
|
||||
await msg.edit_text(
|
||||
f"❌ <b>授权异常</b>\n\n"
|
||||
f"📧 邮箱: <code>{email}</code>\n"
|
||||
f"📝 错误: {str(e)}",
|
||||
parse_mode="HTML"
|
||||
)
|
||||
|
||||
@admin_only
|
||||
async def cmd_run(self, update: Update, context: ContextTypes.DEFAULT_TYPE):
|
||||
"""启动处理指定数量的 Team - 交互式选择"""
|
||||
|
||||
Reference in New Issue
Block a user