第53批:网页绑邮箱三接口+前端向导——不拦截改游戏内60秒批准,密码复核+IP连错5次封5分钟

This commit is contained in:
ypsdf1
2026-10-23 23:01:59 +08:00
parent 3a4252e861
commit f2859fe6e5
3 changed files with 449 additions and 4 deletions
+120
View File
@@ -303,6 +303,12 @@ switch ($action) {
case 'complete_web_register_request':
completeWebRegisterRequest();
break;
case 'check_pending_web_email_bind_requests':
checkPendingWebEmailBindRequests();
break;
case 'web_email_bind_result':
webEmailBindResult();
break;
case 'delete_user':
deleteUser();
break;
@@ -5025,6 +5031,120 @@ function completeWebRegisterRequest() {
success(['request_id' => $requestId, 'status' => $status]);
}
// ===== 第53批:插件轮询待处理的网页邮箱绑定请求(SECRET_KEY认证)=====
function checkPendingWebEmailBindRequests() {
$secret = getParam('secret');
if (!$secret || $secret !== SECRET_KEY) {
error('密钥验证失败', 403);
}
$db = getDB();
try {
$db->exec("SELECT id FROM web_email_bind_requests LIMIT 0");
} catch (\Throwable $e) {
$db->exec("CREATE TABLE IF NOT EXISTS web_email_bind_requests (
id INTEGER PRIMARY KEY AUTOINCREMENT,
player_name TEXT NOT NULL,
email TEXT NOT NULL,
ip_address TEXT DEFAULT '',
status TEXT DEFAULT 'pending',
created_at INTEGER NOT NULL,
expire_at INTEGER NOT NULL,
approved_at INTEGER DEFAULT 0,
processed_at INTEGER DEFAULT 0,
fail_reason TEXT DEFAULT ''
)");
}
$now = time();
// 惰性终结超时未处理的请求(CLI通知1分钟时效)
try {
$db->exec("UPDATE web_email_bind_requests SET status = 'expired', processed_at = " . $now . " WHERE status IN ('pending','notified') AND expire_at < " . $now);
} catch (\Throwable $e) {
@error_log("[checkPendingWebEmailBindRequests] expire error: " . $e->getMessage());
}
// ★ 只读查询不需要BEGIN IMMEDIATE(避免与其它并发请求抢锁导致500)
$stmt = $db->prepare("SELECT id, player_name, email, created_at, expire_at FROM web_email_bind_requests WHERE status = 'pending' ORDER BY created_at ASC");
$result = $stmt->execute();
$requests = array();
$ids = array();
while ($row = $result->fetchArray(SQLITE3_ASSOC)) {
$requests[] = $row;
$ids[] = (int)$row['id'];
}
// 拉取即标记notified(防重复通知;允许失败,下次还会拉到)
if (!empty($ids)) {
try {
$idList = implode(',', $ids);
$db->exec("UPDATE web_email_bind_requests SET status = 'notified' WHERE id IN ($idList) AND status = 'pending'");
} catch (\Throwable $e) {
@error_log("[checkPendingWebEmailBindRequests] mark notified error: " . $e->getMessage());
}
}
success(['requests' => $requests, 'count' => count($requests)]);
}
// ===== 第53批:插件回传游戏内玩家对邮箱绑定请求的处理结果(SECRET_KEY认证)=====
function webEmailBindResult() {
$secret = getParam('secret');
if (!$secret || $secret !== SECRET_KEY) {
error('密钥验证失败', 403);
}
$requestId = getParam('request_id');
$action = getParam('action', ''); // approve / reject / offline / failed
$player = getParam('player', '');
$failReason = getParam('fail_reason', '');
if (!$requestId) error('缺少request_id');
if (!in_array($action, array('approve', 'reject', 'offline', 'failed'), true)) error('非法action');
if (!$player) error('缺少player');
$db = getDB();
$stmt = $db->prepare("SELECT id, player_name, status, expire_at FROM web_email_bind_requests WHERE id = :id");
$stmt->bindValue(':id', (int)$requestId, SQLITE3_INTEGER);
$row = $stmt->execute()->fetchArray(SQLITE3_ASSOC);
if (!$row) error('请求不存在');
if ((string)$row['player_name'] !== (string)$player) error('玩家名不匹配');
$now = time();
$current = (string)$row['status'];
$open = in_array($current, array('pending', 'notified'), true);
if (!$open) {
// 已终结:幂等返回当前状态(重复点击/迟到回调直接忽略,不做任何处置)
success(['request_id' => (int)$requestId, 'status' => $current], '请求已终结,忽略');
return;
}
if ($action === 'approve') {
$newStatus = ($now > (int)$row['expire_at']) ? 'expired' : 'approved';
} elseif ($action === 'reject') {
$newStatus = 'rejected';
} elseif ($action === 'offline') {
$newStatus = 'offline';
} else {
$newStatus = 'failed';
}
$approvedAt = ($newStatus === 'approved') ? $now : 0;
$reason = ($newStatus === 'failed') ? (string)$failReason : '';
$upd = $db->prepare("UPDATE web_email_bind_requests SET status = :status, approved_at = :approved, processed_at = :time, fail_reason = :reason WHERE id = :id");
$upd->bindValue(':status', $newStatus, SQLITE3_TEXT);
$upd->bindValue(':approved', $approvedAt, SQLITE3_INTEGER);
$upd->bindValue(':time', $now, SQLITE3_INTEGER);
$upd->bindValue(':reason', $reason, SQLITE3_TEXT);
$upd->bindValue(':id', (int)$requestId, SQLITE3_INTEGER);
$upd->execute();
success(['request_id' => (int)$requestId, 'status' => $newStatus]);
}
// ===== CDK验证(供sdf1插件调用)=====
// sdf1插件本地CDK未找到时,请求Web后端验证
function validateCdk() {