false, 'error' => __('安全验证失败,请刷新页面重试', 'aksrt')]; } if (empty($post['agree_terms'])) { return ['success' => false, 'error' => __('请先同意服务条款', 'aksrt')]; } if (empty($user_login) || !validate_username($user_login)) { return ['success' => false, 'error' => __('请输入有效的用户名', 'aksrt')]; } if (mb_strlen($user_login) < 3 || mb_strlen($user_login) > 60) { return ['success' => false, 'error' => __('用户名长度需在 3-60 个字符之间', 'aksrt')]; } if (username_exists($user_login)) { return ['success' => false, 'error' => __('该用户名已被使用', 'aksrt')]; } if (empty($user_email) || !is_email($user_email)) { return ['success' => false, 'error' => __('请输入有效的邮箱地址', 'aksrt')]; } if (email_exists($user_email)) { return ['success' => false, 'error' => __('该邮箱已被其他账号使用', 'aksrt')]; } $password_check = self::validate_password($password, $confirm); if ($password_check !== true) { return ['success' => false, 'error' => $password_check]; } if (function_exists('aksrt_require_captcha')) { $captcha_result = aksrt_require_captcha('register', $post); if ($captcha_result !== true) { return ['success' => false, 'error' => $captcha_result]; } } // ====== 解析邀请码 ====== // 优先级:表单 invite_code(用户显式填写) > cookie aksrt_invite $invite_registration_enabled = class_exists('\AKSRT\Settings\Settings') && \AKSRT\Settings\Settings::invite_registration_enabled(); $invite_mode = $invite_registration_enabled && class_exists('\AKSRT\Settings\Settings') ? \AKSRT\Settings\Settings::invite_register_field_mode() : 'hidden'; $invite_code = isset($post['invite_code']) ? sanitize_key((string) wp_unslash($post['invite_code'])) : ''; $resolved_inviter_id = 0; $invite_is_valid = false; if (!$invite_registration_enabled) { // 邀请功能关闭,忽略所有邀请码 $invite_code = ''; } elseif ($invite_code !== '') { if (class_exists('\AKSRT\Credits\Invite')) { $invite_service = \AKSRT\Credits\Invite::get_instance(); $resolved_inviter_id = $invite_service->resolve_code($invite_code); $invite_is_valid = $invite_service->validate_code($invite_code); } // 必填模式下,邀请码无效时根据后台开关决定是否拒绝 $reject_invalid = class_exists('\AKSRT\Settings\Settings') && \AKSRT\Settings\Settings::invite_reject_invalid(); if ($invite_mode === 'required' && $reject_invalid && !$invite_is_valid) { return ['success' => false, 'error' => __('邀请码无效,请检查后重试', 'aksrt')]; } } elseif ($invite_mode === 'required') { return ['success' => false, 'error' => __('请填写邀请码', 'aksrt')]; } // 把解析到的 inviter_id 暂存到静态字段,user_register hook 内部读取(优先于 cookie) self::$pending_invite_inviter_id = $resolved_inviter_id; self::$pending_invite_code = $invite_code; $user_id = wp_create_user($user_login, $password, $user_email); if (is_wp_error($user_id)) { self::$pending_invite_inviter_id = 0; self::$pending_invite_code = ''; return ['success' => false, 'error' => $user_id->get_error_message()]; } if ($invite_code !== '' && $resolved_inviter_id <= 0 && class_exists('\AKSRT\Credits\Invite')) { \AKSRT\Credits\Invite::get_instance()->handle_registration_invite((int) $user_id, $invite_code); } // wp_create_user 内部已触发 user_register hook,\AKSRT\Credits\Invite::on_user_register 已读取 pending 字段。 // 这里清空,避免污染后续请求。 self::$pending_invite_inviter_id = 0; self::$pending_invite_code = ''; $user = get_userdata($user_id); if (!$user || is_wp_error($user)) { return ['success' => false, 'error' => __('注册成功,但读取用户信息失败,请联系管理员', 'aksrt')]; } $oauth_context = isset($context['oauth_bind_data']) && is_array($context['oauth_bind_data']) ? $context['oauth_bind_data'] : []; $oauth_verified = self::oauth_email_is_verified($oauth_context); $requires_verify = \AKSRT\Settings\Settings::registration_requires_email_verification() && !$oauth_verified; if (!$requires_verify) { self::mark_email_verified($user_id); return [ 'success' => true, 'user_id' => (int) $user_id, 'user' => $user, 'user_login' => $user_login, ]; } $method = \AKSRT\Settings\Settings::registration_verification_method(); $begin = self::begin_email_verification( $user, $method, [ 'obk' => sanitize_text_field((string) ($context['obk'] ?? '')), ] ); if (empty($begin['success'])) { self::delete_user_account($user_id); return $begin; } return [ 'success' => true, 'user_id' => (int) $user_id, 'user' => $user, 'user_login' => $user_login, 'verification_required' => true, 'verification_method' => $method, 'verify_url' => self::get_email_verification_url((int) $user_id, ['mode' => $method]), 'message' => $begin['message'] ?? '', ]; } public static function bind_oauth_account(array $post, array $oauth_data): array { if (!wp_verify_nonce($post['_bind_nonce'] ?? '', 'aksrt_bind')) { return ['success' => false, 'error' => __('安全验证失败,请刷新页面重试', 'aksrt')]; } if (function_exists('aksrt_require_captcha')) { $captcha_result = aksrt_require_captcha('bind', $post); if ($captcha_result !== true) { return ['success' => false, 'error' => $captcha_result]; } } $creds = [ 'user_login' => self::resolve_email_to_username((string) ($post['log'] ?? '')), 'user_password' => (string) ($post['pwd'] ?? ''), 'remember' => true, ]; $user = wp_signon($creds); if (is_wp_error($user)) { return ['success' => false, 'error' => self::friendly_login_error($user->get_error_message())]; } if (self::user_requires_email_verification($user)) { wp_logout(); return [ 'success' => false, 'error' => __('该账号尚未完成邮箱验证,请先完成验证后再绑定第三方登录。', 'aksrt'), 'verify_url' => self::get_email_verification_url((int) $user->ID), ]; } $provider = sanitize_key((string) ($oauth_data['provider'] ?? '')); if ($provider === '') { return ['success' => false, 'error' => __('绑定数据无效,请重新使用第三方登录', 'aksrt')]; } $uid = (int) $user->ID; update_user_meta($uid, "aksrt_{$provider}_id", $oauth_data['provider_id'] ?? ''); $bindings = get_user_meta($uid, 'aksrt_oauth_bindings', true) ?: []; if (!is_array($bindings)) { $bindings = []; } if (!in_array($provider, $bindings, true)) { $bindings[] = $provider; } update_user_meta($uid, 'aksrt_oauth_bindings', $bindings); if (!empty($oauth_data['user_data']['avatar_url'])) { update_user_meta($uid, 'aksrt_oauth_avatar', esc_url_raw($oauth_data['user_data']['avatar_url'])); } if (!empty($post['obk'])) { delete_transient(sanitize_text_field((string) $post['obk'])); } wp_set_auth_cookie($uid, true); return [ 'success' => true, 'user' => $user, 'provider' => $provider, ]; } public static function finalize_oauth_registration(int $user_id, array $oauth_data, string $obk = ''): void { if ($user_id <= 0) { return; } $provider = sanitize_key((string) ($oauth_data['provider'] ?? '')); if ($provider === '') { return; } update_user_meta($user_id, "aksrt_{$provider}_id", $oauth_data['provider_id'] ?? ''); update_user_meta($user_id, 'aksrt_oauth_bindings', [$provider]); if (!empty($oauth_data['user_data']['avatar_url'])) { update_user_meta($user_id, 'aksrt_oauth_avatar', esc_url_raw($oauth_data['user_data']['avatar_url'])); } if (self::oauth_email_is_verified($oauth_data)) { EmailVerification::mark_email_verified($user_id); } if ($obk !== '') { delete_transient(sanitize_text_field($obk)); } wp_set_auth_cookie($user_id, true); } public static function get_email_verification_context(array $query): array { $invalid_payload = [ 'mode' => 'invalid', 'user' => null, 'error' => __('验证入口无效或已过期,请重新发起验证流程。', 'aksrt'), 'method' => '', 'email' => '', 'uid' => 0, 'verified' => false, 'access_key' => '', ]; $user_id = isset($query['uid']) ? absint($query['uid']) : 0; if ($user_id <= 0) { return $invalid_payload; } $user = get_userdata($user_id); if (!$user || is_wp_error($user)) { return $invalid_payload; } $method = self::current_registration_verification_method(); $email = (string) get_user_meta($user_id, self::EMAIL_TARGET_META, true); $token = sanitize_text_field((string) ($query['token'] ?? '')); $access = sanitize_text_field((string) ($query['vk'] ?? '')); // 容错:meta 缺失时(例如历史账号被强制要求验证),回退到设置默认值与 user_email if (!in_array($method, ['link', 'code'], true)) { $method = self::current_registration_verification_method(); } if ($email === '' || !is_email($email)) { $email = (string) $user->user_email; } $masked_email = self::masked_email($email); $has_access = self::has_valid_email_access_key($user_id, $access); // token 路径:链接模式直接走 token 校验;不依赖 vk if ($token !== '') { if (EmailVerification::is_email_verified($user_id)) { return [ 'mode' => 'invalid', 'user' => $user, 'error' => __('该验证链接已失效或已使用,请重新发起验证流程', 'aksrt'), 'method' => $has_access ? $method : '', 'email' => $has_access ? $masked_email : '', 'uid' => $has_access ? $user_id : 0, 'verified' => true, 'access_key' => $has_access ? $access : '', ]; } $result = self::verify_email_token($user_id, $token); if (!empty($result['success'])) { return [ 'mode' => 'completed', 'user' => $user, 'error' => '', 'method' => $method, 'email' => $masked_email, 'uid' => $user_id, 'verified' => true, 'redirect' => $result['redirect'] ?? home_url('/'), 'message' => $result['message'] ?? '', 'access_key' => $has_access ? $access : '', ]; } return [ 'mode' => 'invalid', 'user' => $user, 'error' => $result['error'] ?? __('验证链接无效或已过期', 'aksrt'), 'method' => $has_access ? $method : '', 'email' => $has_access ? $masked_email : '', 'uid' => $has_access ? $user_id : 0, 'verified' => false, 'access_key' => $has_access ? $access : '', ]; } // 没有 token 也没有 vk:返回完全脱敏的通用错误,避免根据 uid 枚举账号状态 if (!$has_access) { return $invalid_payload; } if (!self::user_requires_email_verification($user)) { return [ 'mode' => 'verified', 'user' => $user, 'error' => '', 'method' => '', 'email' => self::masked_email((string) $user->user_email), 'uid' => $user_id, 'verified' => true, 'access_key' => $access, ]; } return [ 'mode' => $method === 'code' ? 'code' : 'pending', 'user' => $user, 'error' => '', 'method' => $method, 'email' => $masked_email ?: self::masked_email((string) $user->user_email), 'uid' => $user_id, 'verified' => false, 'access_key' => $access, ]; } public static function verify_email_code_submission(array $post): array { if (!wp_verify_nonce($post['_verify_email_nonce'] ?? '', 'aksrt_verify_email')) { return ['success' => false, 'error' => __('安全验证失败,请刷新页面重试', 'aksrt')]; } $user_id = isset($post['verify_uid']) ? absint($post['verify_uid']) : 0; $access = sanitize_text_field((string) ($post['vk'] ?? '')); $code = sanitize_text_field((string) ($post['email_code'] ?? '')); if ($user_id <= 0 || $code === '') { return ['success' => false, 'error' => __('请输入完整的邮箱验证码', 'aksrt')]; } if (!self::has_valid_email_access_key($user_id, $access)) { return ['success' => false, 'error' => __('验证入口无效或已过期,请重新发起验证流程。', 'aksrt')]; } if (function_exists('aksrt_require_captcha')) { $captcha_result = aksrt_require_captcha('verify_email', $post); if ($captcha_result !== true) { return ['success' => false, 'error' => $captcha_result]; } } return self::verify_email_code($user_id, $code); } public static function resend_email_verification(array $post): array { if (!wp_verify_nonce($post['_verify_email_nonce'] ?? '', 'aksrt_verify_email')) { return ['success' => false, 'error' => __('安全验证失败,请刷新页面重试', 'aksrt')]; } $user_id = isset($post['verify_uid']) ? absint($post['verify_uid']) : 0; $access = sanitize_text_field((string) ($post['vk'] ?? '')); // 必须先持有有效 vk 才允许重发,避免未登录用户用 uid 枚举触发邮件 if ($user_id <= 0 || !self::has_valid_email_access_key($user_id, $access)) { return ['success' => false, 'error' => __('验证入口无效或已过期,请重新发起验证流程。', 'aksrt')]; } // IP 节流:每 IP 每 RESEND_IP_WINDOW 秒最多 RESEND_IP_MAX 次(跨账号合并计数) $ip = sanitize_text_field((string) ($_SERVER['REMOTE_ADDR'] ?? '')); if ($ip !== '') { $ip_key = 'aksrt_email_resend_ip_' . md5($ip); $ip_attempts = (int) get_transient($ip_key); if ($ip_attempts >= self::RESEND_IP_MAX) { self::log_event('verify.resend.ip_throttled', ['uid' => $user_id, 'ip' => $ip]); return ['success' => false, 'error' => __('操作过于频繁,请稍后再试', 'aksrt')]; } set_transient($ip_key, $ip_attempts + 1, self::RESEND_IP_WINDOW); } $user = get_userdata($user_id); if (!$user || is_wp_error($user)) { return ['success' => false, 'error' => __('验证入口无效或已过期,请重新发起验证流程。', 'aksrt')]; } if (!self::user_requires_email_verification($user)) { return ['success' => false, 'error' => __('该账号已完成邮箱验证,无需重复发送', 'aksrt')]; } if (function_exists('aksrt_require_captcha')) { $captcha_result = aksrt_require_captcha('verify_email', $post); if ($captcha_result !== true) { return ['success' => false, 'error' => $captcha_result]; } } $method = self::current_registration_verification_method(); $email = (string) get_user_meta($user_id, self::EMAIL_TARGET_META, true); // 容错:meta 缺失时回退到设置默认值与 user_email(兼容历史账号 / meta 被外部清理的情况) if (!in_array($method, ['link', 'code'], true)) { $method = \AKSRT\Settings\Settings::registration_verification_method(); } if ($email === '' || !is_email($email)) { $email = (string) $user->user_email; } if ($email === '' || !is_email($email)) { return ['success' => false, 'error' => __('当前账号缺少有效邮箱,请联系管理员', 'aksrt')]; } $requested_at = (int) get_user_meta($user_id, self::EMAIL_REQUESTED_AT_META, true); if ($requested_at > 0 && (time() - $requested_at) < 60) { return ['success' => false, 'error' => __('操作过于频繁,请稍后再试', 'aksrt')]; } return self::begin_email_verification($user, $method, [ 'email' => $email, 'obk' => (string) get_user_meta($user_id, self::EMAIL_OBK_META, true), 'force' => true, ]); } private static function user_requires_email_verification($user): bool { return EmailVerification::user_requires_email_verification($user); } private static function mark_email_verified(int $user_id): void { EmailVerification::mark_email_verified($user_id); } // ============================================================ // 公开 API:管理员后台 / 内部业务调用(委托 EmailVerification) // ============================================================ public static function user_is_email_verified(int $user_id): bool { return EmailVerification::user_is_email_verified($user_id); } public static function get_user_verification_state(int $user_id): array { return EmailVerification::get_user_verification_state($user_id); } public static function admin_mark_verified(int $user_id, int $by_admin_id = 0): array { return EmailVerification::admin_mark_verified($user_id, $by_admin_id); } public static function admin_unmark_verified(int $user_id, int $by_admin_id = 0): array { return EmailVerification::admin_unmark_verified($user_id, $by_admin_id); } }