refactor: rename the theme brand and every identifier from AKSRT to Jio
Full-project rename. `git grep -i aksrt` is now empty apart from the
DBMigrator 3.3.0 changelog note that documents the rename itself.
Code identifiers
- PHP namespace AKSRT\ -> Jio\ (composer PSR-4 + 378 declarations)
- global constants AKSRT_* -> JIO_* (VERSION/DIR/URI, PAY_TYPE_*, CAPTCHA_*)
- procedural functions, hooks, options, meta keys, table names,
cookies, query vars, ajax actions and nonces: aksrt_ -> jio_
- text domain aksrt -> jio; Theme Name -> Jio
- JS globals: aksrtData/aksrtAdminData/... -> jioData/jioAdminData/...,
window.AKSRTCaptcha & friends -> window.JioCaptcha, Aksrt* -> Jio*
- Vue components Aks*.vue -> Jio*.vue (15 files renamed + imports)
- CSS classes/data-attrs/custom properties: aksrt- -> jio-
- REST namespace aksrt/v1 -> jio/v1 (incl. payment gateway callbacks)
Storage layer
- DB tables {prefix}aksrt_* -> {prefix}jio_*; SCHEMA_VERSION 3.2.0 -> 3.3.0
so dbDelta creates the new names on install
- widget id_base aksrt_widget_* -> jio_widget_*
- uninstall.php drop list rebuilt from the actual migrator tables
(dropped 3 stale entries, added the 17 missing ones)
Removed
- hardcoded https://api.aksrt.com/version.json default update endpoint;
get_endpoint() now reads the 「更新端点」 setting and do_check() no-ops
when it is empty
Files renamed: inc/helpers/aksrt-*.php -> jio-*.php (54),
assets/admin/src/components/form/Aks*.vue -> Jio*.vue (15).
Build artifacts regenerated: assets/css/build, assets/js/runtime,
assets/admin/build.
Verified: audit-psr4-paths errors=0, audit-admin-contracts errors=0
(warnings=56, unchanged baseline), 813/813 widget-system tests,
44/44 phpunit, php -l clean across all PHP.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
1 parent
5b16bc6e15
commit
35bb96e82f
997 files changed
+28216
-28188
No files matched your search
+216
-216
@@ -1,31 +1,31 @@
|
||||
<?php
|
||||
/**
|
||||
* AKSRT 人机验证(Cloud Captcha)核心。
|
||||
* Jio 人机验证(Cloud Captcha)核心。
|
||||
*
|
||||
* 唯一配置源:option `aksrt_captcha_config`。
|
||||
* 唯一配置源:option `jio_captcha_config`。
|
||||
* 闭环契约:
|
||||
* aksrt_get_captcha_config() -> aksrt_is_captcha_enabled_for(scene)
|
||||
* -> aksrt_render_captcha(scene) -> [data-aksrt-captcha-config] 挂载点
|
||||
* -> captcha-front.js(public bundle)-> 客户端 AKSRTCaptcha + token
|
||||
* -> 业务入口 aksrt_require_captcha(scene, $payload) -> proceed/fail。
|
||||
* jio_get_captcha_config() -> jio_is_captcha_enabled_for(scene)
|
||||
* -> jio_render_captcha(scene) -> [data-jio-captcha-config] 挂载点
|
||||
* -> captcha-front.js(public bundle)-> 客户端 JioCaptcha + token
|
||||
* -> 业务入口 jio_require_captcha(scene, $payload) -> proceed/fail。
|
||||
*
|
||||
* 仅支持云厂商:tencent / aliyun / cloudflare / geetest。
|
||||
* 不含本地图形码 / 本地滑块。
|
||||
*
|
||||
* @package AKSRT
|
||||
* @package Jio
|
||||
*/
|
||||
|
||||
defined('ABSPATH') || exit;
|
||||
|
||||
const AKSRT_CAPTCHA_BROWSER_COOKIE = 'aksrt_captcha_browser';
|
||||
const AKSRT_CAPTCHA_CHALLENGE_PREFIX = 'aksrt_captcha_challenge_';
|
||||
const AKSRT_CAPTCHA_PROOF_PREFIX = 'aksrt_captcha_proof_';
|
||||
const AKSRT_CAPTCHA_CHALLENGE_TTL = 10 * MINUTE_IN_SECONDS;
|
||||
const AKSRT_CAPTCHA_PROOF_TTL = 5 * MINUTE_IN_SECONDS;
|
||||
const JIO_CAPTCHA_BROWSER_COOKIE = 'jio_captcha_browser';
|
||||
const JIO_CAPTCHA_CHALLENGE_PREFIX = 'jio_captcha_challenge_';
|
||||
const JIO_CAPTCHA_PROOF_PREFIX = 'jio_captcha_proof_';
|
||||
const JIO_CAPTCHA_CHALLENGE_TTL = 10 * MINUTE_IN_SECONDS;
|
||||
const JIO_CAPTCHA_PROOF_TTL = 5 * MINUTE_IN_SECONDS;
|
||||
|
||||
function aksrt_captcha_browser_id(): string {
|
||||
$value = isset($_COOKIE[AKSRT_CAPTCHA_BROWSER_COOKIE])
|
||||
? sanitize_text_field(wp_unslash((string) $_COOKIE[AKSRT_CAPTCHA_BROWSER_COOKIE]))
|
||||
function jio_captcha_browser_id(): string {
|
||||
$value = isset($_COOKIE[JIO_CAPTCHA_BROWSER_COOKIE])
|
||||
? sanitize_text_field(wp_unslash((string) $_COOKIE[JIO_CAPTCHA_BROWSER_COOKIE]))
|
||||
: '';
|
||||
if (preg_match('/^[A-Za-z0-9_-]{32,80}$/', $value) === 1) {
|
||||
return $value;
|
||||
@@ -33,7 +33,7 @@ function aksrt_captcha_browser_id(): string {
|
||||
|
||||
$value = rtrim(strtr(base64_encode(random_bytes(32)), '+/', '-_'), '=');
|
||||
if (!headers_sent()) {
|
||||
setcookie(AKSRT_CAPTCHA_BROWSER_COOKIE, $value, [
|
||||
setcookie(JIO_CAPTCHA_BROWSER_COOKIE, $value, [
|
||||
'expires' => time() + MONTH_IN_SECONDS,
|
||||
'path' => defined('COOKIEPATH') && COOKIEPATH ? COOKIEPATH : '/',
|
||||
'domain' => defined('COOKIE_DOMAIN') ? COOKIE_DOMAIN : '',
|
||||
@@ -42,29 +42,29 @@ function aksrt_captcha_browser_id(): string {
|
||||
'samesite' => 'Lax',
|
||||
]);
|
||||
}
|
||||
$_COOKIE[AKSRT_CAPTCHA_BROWSER_COOKIE] = $value;
|
||||
$_COOKIE[JIO_CAPTCHA_BROWSER_COOKIE] = $value;
|
||||
return $value;
|
||||
}
|
||||
|
||||
function aksrt_captcha_challenge_key(string $token): string {
|
||||
return AKSRT_CAPTCHA_CHALLENGE_PREFIX . hash('sha256', trim($token));
|
||||
function jio_captcha_challenge_key(string $token): string {
|
||||
return JIO_CAPTCHA_CHALLENGE_PREFIX . hash('sha256', trim($token));
|
||||
}
|
||||
|
||||
function aksrt_captcha_challenge_material(string $scene, string $provider, string $nonce, int $timestamp): string {
|
||||
function jio_captcha_challenge_material(string $scene, string $provider, string $nonce, int $timestamp): string {
|
||||
$host = strtolower((string) wp_parse_url(home_url('/'), PHP_URL_HOST));
|
||||
return sanitize_key($scene) . '|' . sanitize_key($provider) . '|'
|
||||
. hash('sha256', aksrt_captcha_browser_id()) . '|' . $host . '|' . $timestamp . '|' . $nonce;
|
||||
. hash('sha256', jio_captcha_browser_id()) . '|' . $host . '|' . $timestamp . '|' . $nonce;
|
||||
}
|
||||
|
||||
function aksrt_captcha_issue_challenge(string $scene, string $provider): string {
|
||||
function jio_captcha_issue_challenge(string $scene, string $provider): string {
|
||||
$nonce = rtrim(strtr(base64_encode(random_bytes(32)), '+/', '-_'), '=');
|
||||
$timestamp = time();
|
||||
$material = aksrt_captcha_challenge_material($scene, $provider, $nonce, $timestamp);
|
||||
$material = jio_captcha_challenge_material($scene, $provider, $nonce, $timestamp);
|
||||
$signature = hash_hmac('sha256', $material, wp_salt('auth'));
|
||||
return $nonce . '.' . $timestamp . '.' . $signature;
|
||||
}
|
||||
|
||||
function aksrt_captcha_challenge_valid(string $token, string $scene, string $provider): bool {
|
||||
function jio_captcha_challenge_valid(string $token, string $scene, string $provider): bool {
|
||||
$parts = explode('.', trim($token));
|
||||
if (count($parts) !== 3) {
|
||||
return false;
|
||||
@@ -74,22 +74,22 @@ function aksrt_captcha_challenge_valid(string $token, string $scene, string $pro
|
||||
return false;
|
||||
}
|
||||
$timestamp = (int) $raw_timestamp;
|
||||
if ($timestamp > time() + 60 || $timestamp < time() - AKSRT_CAPTCHA_CHALLENGE_TTL) {
|
||||
if ($timestamp > time() + 60 || $timestamp < time() - JIO_CAPTCHA_CHALLENGE_TTL) {
|
||||
return false;
|
||||
}
|
||||
$expected = hash_hmac(
|
||||
'sha256',
|
||||
aksrt_captcha_challenge_material($scene, $provider, $nonce, $timestamp),
|
||||
jio_captcha_challenge_material($scene, $provider, $nonce, $timestamp),
|
||||
wp_salt('auth')
|
||||
);
|
||||
return hash_equals($expected, $signature);
|
||||
}
|
||||
|
||||
function aksrt_captcha_validate_challenge(string $token, string $scene, string $provider, bool $claim = false): bool {
|
||||
if (!aksrt_captcha_challenge_valid($token, $scene, $provider)) {
|
||||
function jio_captcha_validate_challenge(string $token, string $scene, string $provider, bool $claim = false): bool {
|
||||
if (!jio_captcha_challenge_valid($token, $scene, $provider)) {
|
||||
return false;
|
||||
}
|
||||
$key = aksrt_captcha_challenge_key($token);
|
||||
$key = jio_captcha_challenge_key($token);
|
||||
if (!$claim) {
|
||||
$current = get_option($key, null);
|
||||
if (is_numeric($current) && (int) $current < time()) {
|
||||
@@ -103,15 +103,15 @@ function aksrt_captcha_validate_challenge(string $token, string $scene, string $
|
||||
if (is_numeric($current) && (int) $current < time()) {
|
||||
delete_option($key);
|
||||
}
|
||||
return add_option($key, time() + AKSRT_CAPTCHA_CHALLENGE_TTL, '', false);
|
||||
return add_option($key, time() + JIO_CAPTCHA_CHALLENGE_TTL, '', false);
|
||||
}
|
||||
|
||||
function aksrt_captcha_challenge_release(string $token): void {
|
||||
delete_option(aksrt_captcha_challenge_key($token));
|
||||
function jio_captcha_challenge_release(string $token): void {
|
||||
delete_option(jio_captcha_challenge_key($token));
|
||||
}
|
||||
|
||||
function aksrt_captcha_rate_limited(string $scope, string $subject, int $limit = 30, int $ttl = 60): bool {
|
||||
$key = 'aksrt_captcha_rl_' . md5($scope . '|' . strtolower($subject));
|
||||
function jio_captcha_rate_limited(string $scope, string $subject, int $limit = 30, int $ttl = 60): bool {
|
||||
$key = 'jio_captcha_rl_' . md5($scope . '|' . strtolower($subject));
|
||||
$count = (int) get_transient($key);
|
||||
if ($count >= $limit) {
|
||||
return true;
|
||||
@@ -120,37 +120,37 @@ function aksrt_captcha_rate_limited(string $scope, string $subject, int $limit =
|
||||
return false;
|
||||
}
|
||||
|
||||
function aksrt_captcha_proof_key(string $token): string {
|
||||
return AKSRT_CAPTCHA_PROOF_PREFIX . hash('sha256', trim($token));
|
||||
function jio_captcha_proof_key(string $token): string {
|
||||
return JIO_CAPTCHA_PROOF_PREFIX . hash('sha256', trim($token));
|
||||
}
|
||||
|
||||
function aksrt_captcha_issue_proof(string $scene, string $provider): string {
|
||||
function jio_captcha_issue_proof(string $scene, string $provider): string {
|
||||
$token = rtrim(strtr(base64_encode(random_bytes(32)), '+/', '-_'), '=');
|
||||
$row = [
|
||||
'scene' => sanitize_key($scene),
|
||||
'provider' => sanitize_key($provider),
|
||||
'browser_hash' => hash('sha256', aksrt_captcha_browser_id()),
|
||||
'browser_hash' => hash('sha256', jio_captcha_browser_id()),
|
||||
'host' => strtolower((string) wp_parse_url(home_url('/'), PHP_URL_HOST)),
|
||||
'expires_at' => time() + AKSRT_CAPTCHA_PROOF_TTL,
|
||||
'expires_at' => time() + JIO_CAPTCHA_PROOF_TTL,
|
||||
];
|
||||
if (!add_option(aksrt_captcha_proof_key($token), $row, '', false)) {
|
||||
if (!add_option(jio_captcha_proof_key($token), $row, '', false)) {
|
||||
throw new \RuntimeException('captcha_proof_issue_failed');
|
||||
}
|
||||
return $token;
|
||||
}
|
||||
|
||||
function aksrt_captcha_consume_proof(string $token, string $scene, string $provider): bool {
|
||||
function jio_captcha_consume_proof(string $token, string $scene, string $provider): bool {
|
||||
if ($token === '') {
|
||||
return false;
|
||||
}
|
||||
$key = aksrt_captcha_proof_key($token);
|
||||
$key = jio_captcha_proof_key($token);
|
||||
$row = get_option($key, null);
|
||||
$host = strtolower((string) wp_parse_url(home_url('/'), PHP_URL_HOST));
|
||||
$valid = is_array($row)
|
||||
&& (int) ($row['expires_at'] ?? 0) >= time()
|
||||
&& hash_equals(sanitize_key($scene), (string) ($row['scene'] ?? ''))
|
||||
&& hash_equals(sanitize_key($provider), (string) ($row['provider'] ?? ''))
|
||||
&& hash_equals(hash('sha256', aksrt_captcha_browser_id()), (string) ($row['browser_hash'] ?? ''))
|
||||
&& hash_equals(hash('sha256', jio_captcha_browser_id()), (string) ($row['browser_hash'] ?? ''))
|
||||
&& $host !== ''
|
||||
&& hash_equals($host, (string) ($row['host'] ?? ''));
|
||||
if (!$valid) {
|
||||
@@ -173,9 +173,9 @@ function aksrt_captcha_consume_proof(string $token, string $scene, string $provi
|
||||
return true;
|
||||
}
|
||||
|
||||
function aksrt_captcha_cleanup_records(int $limit = 200): int {
|
||||
function jio_captcha_cleanup_records(int $limit = 200): int {
|
||||
global $wpdb;
|
||||
$prefixes = [AKSRT_CAPTCHA_CHALLENGE_PREFIX, AKSRT_CAPTCHA_PROOF_PREFIX];
|
||||
$prefixes = [JIO_CAPTCHA_CHALLENGE_PREFIX, JIO_CAPTCHA_PROOF_PREFIX];
|
||||
$removed = 0;
|
||||
foreach ($prefixes as $prefix) {
|
||||
$rows = $wpdb->get_results($wpdb->prepare(
|
||||
@@ -196,68 +196,68 @@ function aksrt_captcha_cleanup_records(int $limit = 200): int {
|
||||
|
||||
add_action('init', static function (): void {
|
||||
if (wp_rand(1, 100) === 1) {
|
||||
aksrt_captcha_cleanup_records();
|
||||
jio_captcha_cleanup_records();
|
||||
}
|
||||
}, 30);
|
||||
|
||||
add_action('rest_api_init', static function (): void {
|
||||
register_rest_route('aksrt/v1', '/captcha/challenge', [
|
||||
register_rest_route('jio/v1', '/captcha/challenge', [
|
||||
'methods' => 'POST',
|
||||
'permission_callback' => '__return_true',
|
||||
'callback' => static function (\WP_REST_Request $request) {
|
||||
$data = $request->get_json_params();
|
||||
$scene = sanitize_key((string) (is_array($data) ? ($data['scene'] ?? '') : ''));
|
||||
if (!aksrt_is_captcha_enabled_for($scene)) {
|
||||
return new \WP_Error('aksrt_captcha_scene', __('人机验证场景未启用', 'aksrt'), ['status' => 400]);
|
||||
if (!jio_is_captcha_enabled_for($scene)) {
|
||||
return new \WP_Error('jio_captcha_scene', __('人机验证场景未启用', 'jio'), ['status' => 400]);
|
||||
}
|
||||
$cfg = aksrt_get_captcha_config();
|
||||
$cfg = jio_get_captcha_config();
|
||||
$provider = $cfg['active_provider'];
|
||||
if ($provider === '' || !aksrt_captcha_provider_is_configured($provider, $cfg[$provider] ?? [])) {
|
||||
return new \WP_Error('aksrt_captcha_config', __('人机验证配置不完整', 'aksrt'), ['status' => 503]);
|
||||
if ($provider === '' || !jio_captcha_provider_is_configured($provider, $cfg[$provider] ?? [])) {
|
||||
return new \WP_Error('jio_captcha_config', __('人机验证配置不完整', 'jio'), ['status' => 503]);
|
||||
}
|
||||
if (aksrt_captcha_rate_limited('challenge:' . $scene, aksrt_get_client_ip(), 20, MINUTE_IN_SECONDS)) {
|
||||
return new \WP_Error('aksrt_captcha_rate', __('请求过于频繁,请稍后再试', 'aksrt'), ['status' => 429]);
|
||||
if (jio_captcha_rate_limited('challenge:' . $scene, jio_get_client_ip(), 20, MINUTE_IN_SECONDS)) {
|
||||
return new \WP_Error('jio_captcha_rate', __('请求过于频繁,请稍后再试', 'jio'), ['status' => 429]);
|
||||
}
|
||||
return new \WP_REST_Response([
|
||||
'success' => true,
|
||||
'data' => ['challenge' => aksrt_captcha_issue_challenge($scene, $provider)],
|
||||
'data' => ['challenge' => jio_captcha_issue_challenge($scene, $provider)],
|
||||
], 200);
|
||||
},
|
||||
]);
|
||||
register_rest_route('aksrt/v1', '/captcha/exchange', [
|
||||
register_rest_route('jio/v1', '/captcha/exchange', [
|
||||
'methods' => 'POST',
|
||||
'permission_callback' => '__return_true',
|
||||
'callback' => static function (\WP_REST_Request $request) {
|
||||
$data = $request->get_json_params();
|
||||
$data = is_array($data) ? $data : [];
|
||||
$scene = sanitize_key((string) ($data['scene'] ?? ''));
|
||||
if (!aksrt_is_captcha_enabled_for($scene)) {
|
||||
return new \WP_Error('aksrt_captcha_scene', __('人机验证场景未启用', 'aksrt'), ['status' => 400]);
|
||||
if (!jio_is_captcha_enabled_for($scene)) {
|
||||
return new \WP_Error('jio_captcha_scene', __('人机验证场景未启用', 'jio'), ['status' => 400]);
|
||||
}
|
||||
$cfg = aksrt_get_captcha_config();
|
||||
$cfg = jio_get_captcha_config();
|
||||
$provider = $cfg['active_provider'];
|
||||
$pcfg = $cfg[$provider] ?? [];
|
||||
if ($provider === '' || !aksrt_captcha_provider_is_configured($provider, $pcfg)) {
|
||||
return new \WP_Error('aksrt_captcha_config', __('人机验证配置不完整', 'aksrt'), ['status' => 503]);
|
||||
if ($provider === '' || !jio_captcha_provider_is_configured($provider, $pcfg)) {
|
||||
return new \WP_Error('jio_captcha_config', __('人机验证配置不完整', 'jio'), ['status' => 503]);
|
||||
}
|
||||
$challenge = sanitize_text_field((string) ($data['aksrt_captcha_challenge'] ?? ''));
|
||||
if (!aksrt_captcha_validate_challenge($challenge, $scene, $provider, false)) {
|
||||
return new \WP_Error('aksrt_captcha_challenge', __('人机验证会话无效或已过期,请重试', 'aksrt'), ['status' => 400]);
|
||||
$challenge = sanitize_text_field((string) ($data['jio_captcha_challenge'] ?? ''));
|
||||
if (!jio_captcha_validate_challenge($challenge, $scene, $provider, false)) {
|
||||
return new \WP_Error('jio_captcha_challenge', __('人机验证会话无效或已过期,请重试', 'jio'), ['status' => 400]);
|
||||
}
|
||||
// 原子占用 challenge:并发请求只有首个能进入厂商验签,其余直接 409,避免同一票据放大厂商调用。
|
||||
if (!aksrt_captcha_validate_challenge($challenge, $scene, $provider, true)) {
|
||||
return new \WP_Error('aksrt_captcha_replayed', __('人机验证会话已在验证中,请重试', 'aksrt'), ['status' => 409]);
|
||||
if (!jio_captcha_validate_challenge($challenge, $scene, $provider, true)) {
|
||||
return new \WP_Error('jio_captcha_replayed', __('人机验证会话已在验证中,请重试', 'jio'), ['status' => 409]);
|
||||
}
|
||||
$result = aksrt_verify_captcha_provider($provider, $pcfg, $data, aksrt_get_client_ip(), $scene);
|
||||
$result = jio_verify_captcha_provider($provider, $pcfg, $data, jio_get_client_ip(), $scene);
|
||||
if (is_wp_error($result)) {
|
||||
aksrt_captcha_challenge_release($challenge);
|
||||
jio_captcha_challenge_release($challenge);
|
||||
return $result;
|
||||
}
|
||||
try {
|
||||
$proof = aksrt_captcha_issue_proof($scene, $provider);
|
||||
$proof = jio_captcha_issue_proof($scene, $provider);
|
||||
} catch (\Throwable $e) {
|
||||
aksrt_captcha_challenge_release($challenge);
|
||||
return new \WP_Error('aksrt_captcha_proof', __('无法创建人机验证凭证,请重试', 'aksrt'), ['status' => 500]);
|
||||
jio_captcha_challenge_release($challenge);
|
||||
return new \WP_Error('jio_captcha_proof', __('无法创建人机验证凭证,请重试', 'jio'), ['status' => 500]);
|
||||
}
|
||||
return new \WP_REST_Response([
|
||||
'success' => true,
|
||||
@@ -267,10 +267,10 @@ add_action('rest_api_init', static function (): void {
|
||||
]);
|
||||
});
|
||||
|
||||
function aksrt_captcha_provider_metadata(): array {
|
||||
function jio_captcha_provider_metadata(): array {
|
||||
return [
|
||||
'tencent' => [
|
||||
'label' => __('腾讯云 Captcha', 'aksrt'),
|
||||
'label' => __('腾讯云 Captcha', 'jio'),
|
||||
'fields' => [
|
||||
'secret_id' => ['default' => '', 'required' => true],
|
||||
'secret_key' => ['default' => '', 'required' => true, 'secret' => true],
|
||||
@@ -279,7 +279,7 @@ function aksrt_captcha_provider_metadata(): array {
|
||||
],
|
||||
],
|
||||
'aliyun' => [
|
||||
'label' => __('阿里云 CAPTCHA 2.0', 'aksrt'),
|
||||
'label' => __('阿里云 CAPTCHA 2.0', 'jio'),
|
||||
'fields' => [
|
||||
'region' => ['default' => 'cn', 'required' => true, 'values' => ['cn', 'sgp']],
|
||||
'prefix' => ['default' => '', 'required' => true],
|
||||
@@ -289,7 +289,7 @@ function aksrt_captcha_provider_metadata(): array {
|
||||
],
|
||||
],
|
||||
'cloudflare' => [
|
||||
'label' => __('Cloudflare Turnstile', 'aksrt'),
|
||||
'label' => __('Cloudflare Turnstile', 'jio'),
|
||||
'fields' => [
|
||||
'site_key' => ['default' => '', 'required' => true],
|
||||
'secret_key' => ['default' => '', 'required' => true, 'secret' => true],
|
||||
@@ -298,7 +298,7 @@ function aksrt_captcha_provider_metadata(): array {
|
||||
],
|
||||
],
|
||||
'geetest' => [
|
||||
'label' => __('极验 GeeTest', 'aksrt'),
|
||||
'label' => __('极验 GeeTest', 'jio'),
|
||||
'fields' => [
|
||||
'captcha_id' => ['default' => '', 'required' => true],
|
||||
'captcha_key' => ['default' => '', 'required' => true, 'secret' => true],
|
||||
@@ -311,15 +311,15 @@ function aksrt_captcha_provider_metadata(): array {
|
||||
/**
|
||||
* 支持的验证服务商。
|
||||
*/
|
||||
function aksrt_captcha_providers(): array {
|
||||
return array_keys(aksrt_captcha_provider_metadata());
|
||||
function jio_captcha_providers(): array {
|
||||
return array_keys(jio_captcha_provider_metadata());
|
||||
}
|
||||
|
||||
/**
|
||||
* 服务商字段白名单与默认值。
|
||||
*/
|
||||
function aksrt_captcha_provider_defaults(string $provider): array {
|
||||
$fields = aksrt_captcha_provider_metadata()[$provider]['fields'] ?? [];
|
||||
function jio_captcha_provider_defaults(string $provider): array {
|
||||
$fields = jio_captcha_provider_metadata()[$provider]['fields'] ?? [];
|
||||
$defaults = [];
|
||||
foreach ($fields as $key => $meta) {
|
||||
$defaults[$key] = $meta['default'] ?? '';
|
||||
@@ -330,21 +330,21 @@ function aksrt_captcha_provider_defaults(string $provider): array {
|
||||
/**
|
||||
* 服务商 secret 字段。
|
||||
*/
|
||||
function aksrt_captcha_provider_secret_fields(string $provider): array {
|
||||
$fields = aksrt_captcha_provider_metadata()[$provider]['fields'] ?? [];
|
||||
function jio_captcha_provider_secret_fields(string $provider): array {
|
||||
$fields = jio_captcha_provider_metadata()[$provider]['fields'] ?? [];
|
||||
return array_values(array_keys(array_filter($fields, static fn(array $meta): bool => !empty($meta['secret']))));
|
||||
}
|
||||
|
||||
/**
|
||||
* 按集中元数据规范化服务商配置,丢弃未知键。
|
||||
*/
|
||||
function aksrt_captcha_sanitize_provider_config(string $provider, $raw): array {
|
||||
$meta = aksrt_captcha_provider_metadata()[$provider]['fields'] ?? [];
|
||||
function jio_captcha_sanitize_provider_config(string $provider, $raw): array {
|
||||
$meta = jio_captcha_provider_metadata()[$provider]['fields'] ?? [];
|
||||
if ($meta === []) {
|
||||
return [];
|
||||
}
|
||||
$raw = is_array($raw) ? $raw : [];
|
||||
$clean = aksrt_captcha_provider_defaults($provider);
|
||||
$clean = jio_captcha_provider_defaults($provider);
|
||||
foreach ($meta as $key => $field) {
|
||||
if (!array_key_exists($key, $raw) || is_array($raw[$key]) || is_object($raw[$key])) {
|
||||
continue;
|
||||
@@ -361,36 +361,36 @@ function aksrt_captcha_sanitize_provider_config(string $provider, $raw): array {
|
||||
/**
|
||||
* 人机验证场景白名单。
|
||||
*/
|
||||
function aksrt_captcha_scenes(): array {
|
||||
function jio_captcha_scenes(): array {
|
||||
return [
|
||||
'comment' => __('发表评论', 'aksrt'),
|
||||
'login' => __('用户登录', 'aksrt'),
|
||||
'register' => __('用户注册', 'aksrt'),
|
||||
'bind' => __('绑定第三方', 'aksrt'),
|
||||
'bind_phone' => __('绑定手机', 'aksrt'),
|
||||
'lostpassword' => __('找回密码', 'aksrt'),
|
||||
'change_password' => __('修改密码', 'aksrt'),
|
||||
'change_email' => __('更改邮箱', 'aksrt'),
|
||||
'download' => __('资源下载', 'aksrt'),
|
||||
'signin' => __('每日签到', 'aksrt'),
|
||||
'front_submit' => __('前台投稿', 'aksrt'),
|
||||
'tip_user' => __('打赏用户', 'aksrt'),
|
||||
'ticket_create' => __('提交工单', 'aksrt'),
|
||||
'ticket_reply' => __('回复工单', 'aksrt'),
|
||||
'comment' => __('发表评论', 'jio'),
|
||||
'login' => __('用户登录', 'jio'),
|
||||
'register' => __('用户注册', 'jio'),
|
||||
'bind' => __('绑定第三方', 'jio'),
|
||||
'bind_phone' => __('绑定手机', 'jio'),
|
||||
'lostpassword' => __('找回密码', 'jio'),
|
||||
'change_password' => __('修改密码', 'jio'),
|
||||
'change_email' => __('更改邮箱', 'jio'),
|
||||
'download' => __('资源下载', 'jio'),
|
||||
'signin' => __('每日签到', 'jio'),
|
||||
'front_submit' => __('前台投稿', 'jio'),
|
||||
'tip_user' => __('打赏用户', 'jio'),
|
||||
'ticket_create' => __('提交工单', 'jio'),
|
||||
'ticket_reply' => __('回复工单', 'jio'),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* 默认配置结构。
|
||||
*/
|
||||
function aksrt_captcha_default_config(): array {
|
||||
function jio_captcha_default_config(): array {
|
||||
$config = [
|
||||
'enabled' => false,
|
||||
'active_provider' => '',
|
||||
'enabled_scenarios' => [],
|
||||
];
|
||||
foreach (aksrt_captcha_providers() as $provider) {
|
||||
$config[$provider] = aksrt_captcha_provider_defaults($provider);
|
||||
foreach (jio_captcha_providers() as $provider) {
|
||||
$config[$provider] = jio_captcha_provider_defaults($provider);
|
||||
}
|
||||
return $config;
|
||||
}
|
||||
@@ -401,12 +401,12 @@ function aksrt_captcha_default_config(): array {
|
||||
* @param mixed $raw
|
||||
* @return array<int, string>
|
||||
*/
|
||||
function aksrt_captcha_sanitize_scene_list($raw): array {
|
||||
function jio_captcha_sanitize_scene_list($raw): array {
|
||||
$list = is_array($raw) ? $raw : [];
|
||||
$clean = [];
|
||||
foreach ($list as $scene) {
|
||||
$scene = sanitize_key((string) $scene);
|
||||
if ($scene !== '' && array_key_exists($scene, aksrt_captcha_scenes()) && !in_array($scene, $clean, true)) {
|
||||
if ($scene !== '' && array_key_exists($scene, jio_captcha_scenes()) && !in_array($scene, $clean, true)) {
|
||||
$clean[] = $scene;
|
||||
}
|
||||
}
|
||||
@@ -416,33 +416,33 @@ function aksrt_captcha_sanitize_scene_list($raw): array {
|
||||
/**
|
||||
* 获取人机验证完整配置(规范化,不合并历史脏键)。
|
||||
*
|
||||
* 结果在同一请求内缓存;后台保存后调用 aksrt_captcha_config_reset() 失效。
|
||||
* 结果在同一请求内缓存;后台保存后调用 jio_captcha_config_reset() 失效。
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
function aksrt_get_captcha_config(): array {
|
||||
$cache =& $GLOBALS['aksrt_captcha_config_cache'];
|
||||
function jio_get_captcha_config(): array {
|
||||
$cache =& $GLOBALS['jio_captcha_config_cache'];
|
||||
if (is_array($cache)) {
|
||||
return $cache;
|
||||
}
|
||||
|
||||
$stored = get_option('aksrt_captcha_config', []);
|
||||
$cfg = array_merge(aksrt_captcha_default_config(), is_array($stored) ? $stored : []);
|
||||
$stored = get_option('jio_captcha_config', []);
|
||||
$cfg = array_merge(jio_captcha_default_config(), is_array($stored) ? $stored : []);
|
||||
|
||||
$provider = isset($cfg['active_provider']) ? sanitize_key((string) $cfg['active_provider']) : '';
|
||||
if (!in_array($provider, aksrt_captcha_providers(), true)) {
|
||||
if (!in_array($provider, jio_captcha_providers(), true)) {
|
||||
$provider = '';
|
||||
}
|
||||
|
||||
$enabled = aksrt_captcha_sanitize_scene_list($cfg['enabled_scenarios'] ?? []);
|
||||
$enabled = jio_captcha_sanitize_scene_list($cfg['enabled_scenarios'] ?? []);
|
||||
|
||||
$result = [
|
||||
'enabled' => !empty($cfg['enabled']),
|
||||
'active_provider' => $provider,
|
||||
'enabled_scenarios' => $enabled,
|
||||
];
|
||||
foreach (aksrt_captcha_providers() as $p) {
|
||||
$result[$p] = aksrt_captcha_sanitize_provider_config($p, $cfg[$p] ?? []);
|
||||
foreach (jio_captcha_providers() as $p) {
|
||||
$result[$p] = jio_captcha_sanitize_provider_config($p, $cfg[$p] ?? []);
|
||||
}
|
||||
|
||||
$cache = $result;
|
||||
@@ -452,26 +452,26 @@ function aksrt_get_captcha_config(): array {
|
||||
/**
|
||||
* 使请求内的配置缓存失效(后台保存路径调用)。
|
||||
*/
|
||||
function aksrt_captcha_config_reset(): void {
|
||||
$GLOBALS['aksrt_captcha_config_cache'] = null;
|
||||
function jio_captcha_config_reset(): void {
|
||||
$GLOBALS['jio_captcha_config_cache'] = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 各服务商必填字段。
|
||||
*/
|
||||
function aksrt_captcha_required_fields(string $provider): array {
|
||||
$fields = aksrt_captcha_provider_metadata()[$provider]['fields'] ?? [];
|
||||
function jio_captcha_required_fields(string $provider): array {
|
||||
$fields = jio_captcha_provider_metadata()[$provider]['fields'] ?? [];
|
||||
return array_values(array_keys(array_filter($fields, static fn(array $meta): bool => !empty($meta['required']))));
|
||||
}
|
||||
|
||||
/**
|
||||
* 当前服务商必填凭据是否齐全(避免空 captcha_id 打到第三方 403)。
|
||||
*/
|
||||
function aksrt_captcha_provider_is_configured(string $provider, array $pcfg = []): bool {
|
||||
if (!in_array($provider, aksrt_captcha_providers(), true)) {
|
||||
function jio_captcha_provider_is_configured(string $provider, array $pcfg = []): bool {
|
||||
if (!in_array($provider, jio_captcha_providers(), true)) {
|
||||
return false;
|
||||
}
|
||||
$required = aksrt_captcha_required_fields($provider);
|
||||
$required = jio_captcha_required_fields($provider);
|
||||
if (empty($required)) {
|
||||
return false;
|
||||
}
|
||||
@@ -486,16 +486,16 @@ function aksrt_captcha_provider_is_configured(string $provider, array $pcfg = []
|
||||
/**
|
||||
* 指定场景是否启用人机验证。
|
||||
*
|
||||
* @param string $scene 见 aksrt_captcha_scenes()
|
||||
* @param string $scene 见 jio_captcha_scenes()
|
||||
* @return bool
|
||||
*/
|
||||
function aksrt_is_captcha_enabled_for($scene): bool {
|
||||
function jio_is_captcha_enabled_for($scene): bool {
|
||||
$scene = sanitize_key((string) $scene);
|
||||
if (!array_key_exists($scene, aksrt_captcha_scenes())) {
|
||||
if (!array_key_exists($scene, jio_captcha_scenes())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$cfg = aksrt_get_captcha_config();
|
||||
$cfg = jio_get_captcha_config();
|
||||
if (empty($cfg['enabled'])) {
|
||||
return false;
|
||||
}
|
||||
@@ -510,20 +510,20 @@ function aksrt_is_captcha_enabled_for($scene): bool {
|
||||
* @param array $payload 客户端提交的验证字段
|
||||
* @return true|\WP_Error 成功返回 true,失败返回 WP_Error
|
||||
*/
|
||||
function aksrt_require_captcha(string $scene, array $payload = []) {
|
||||
if (!aksrt_is_captcha_enabled_for($scene)) {
|
||||
function jio_require_captcha(string $scene, array $payload = []) {
|
||||
if (!jio_is_captcha_enabled_for($scene)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
$cfg = aksrt_get_captcha_config();
|
||||
$cfg = jio_get_captcha_config();
|
||||
$provider = $cfg['active_provider'];
|
||||
if ($provider === '' || !aksrt_captcha_provider_is_configured($provider, $cfg[$provider] ?? [])) {
|
||||
return aksrt_captcha_error('aksrt_captcha_config', __('人机验证配置不完整,请联系站点管理员', 'aksrt'));
|
||||
if ($provider === '' || !jio_captcha_provider_is_configured($provider, $cfg[$provider] ?? [])) {
|
||||
return jio_captcha_error('jio_captcha_config', __('人机验证配置不完整,请联系站点管理员', 'jio'));
|
||||
}
|
||||
|
||||
$proof = sanitize_text_field((string) ($payload['aksrt_captcha_proof'] ?? ''));
|
||||
if (!aksrt_captcha_consume_proof($proof, $scene, $provider)) {
|
||||
return aksrt_captcha_error('aksrt_captcha_proof', __('人机验证凭证无效、已过期或已使用,请重试', 'aksrt'));
|
||||
$proof = sanitize_text_field((string) ($payload['jio_captcha_proof'] ?? ''));
|
||||
if (!jio_captcha_consume_proof($proof, $scene, $provider)) {
|
||||
return jio_captcha_error('jio_captcha_proof', __('人机验证凭证无效、已过期或已使用,请重试', 'jio'));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@@ -531,17 +531,17 @@ function aksrt_require_captcha(string $scene, array $payload = []) {
|
||||
/**
|
||||
* 后台摘要:enabled / provider / configured / 场景命中状态。
|
||||
*/
|
||||
function aksrt_get_captcha_status_summary(): array {
|
||||
$cfg = aksrt_get_captcha_config();
|
||||
function jio_get_captcha_status_summary(): array {
|
||||
$cfg = jio_get_captcha_config();
|
||||
$provider = $cfg['active_provider'];
|
||||
$scenes = [];
|
||||
foreach (aksrt_captcha_scenes() as $key => $label) {
|
||||
$scenes[$key] = aksrt_is_captcha_enabled_for($key);
|
||||
foreach (jio_captcha_scenes() as $key => $label) {
|
||||
$scenes[$key] = jio_is_captcha_enabled_for($key);
|
||||
}
|
||||
return [
|
||||
'enabled' => !empty($cfg['enabled']),
|
||||
'provider' => $provider,
|
||||
'configured' => $provider !== '' && aksrt_captcha_provider_is_configured($provider, $cfg[$provider] ?? []),
|
||||
'configured' => $provider !== '' && jio_captcha_provider_is_configured($provider, $cfg[$provider] ?? []),
|
||||
'scenes' => $scenes,
|
||||
];
|
||||
}
|
||||
@@ -553,17 +553,17 @@ add_action('admin_notices', static function () {
|
||||
if (!current_user_can('manage_options')) {
|
||||
return;
|
||||
}
|
||||
$cfg = aksrt_get_captcha_config();
|
||||
$cfg = jio_get_captcha_config();
|
||||
if (empty($cfg['enabled']) || $cfg['active_provider'] === '') {
|
||||
return;
|
||||
}
|
||||
$provider = $cfg['active_provider'];
|
||||
if (aksrt_captcha_provider_is_configured($provider, $cfg[$provider] ?? [])) {
|
||||
if (jio_captcha_provider_is_configured($provider, $cfg[$provider] ?? [])) {
|
||||
return;
|
||||
}
|
||||
echo '<div class="notice notice-error"><p>' . esc_html(sprintf(
|
||||
/* translators: %s: captcha provider key */
|
||||
__('人机验证服务商「%s」已启用但凭据未配齐,已启用场景将拒绝请求。请到「功能&权限 → 人机验证」补全配置。', 'aksrt'),
|
||||
__('人机验证服务商「%s」已启用但凭据未配齐,已启用场景将拒绝请求。请到「功能&权限 → 人机验证」补全配置。', 'jio'),
|
||||
$provider
|
||||
)) . '</p></div>';
|
||||
});
|
||||
@@ -572,13 +572,13 @@ add_action('admin_notices', static function () {
|
||||
// 客户端真实 IP(穿透 CDN / 代理)
|
||||
// ============================================================
|
||||
|
||||
function aksrt_get_client_ip(): string {
|
||||
function jio_get_client_ip(): string {
|
||||
$remote = isset($_SERVER['REMOTE_ADDR']) ? (string) $_SERVER['REMOTE_ADDR'] : '';
|
||||
|
||||
// 信任代理名单:过滤返回非空 CIDR/IP 列表时,仅当 REMOTE_ADDR 命中名单
|
||||
// 才采纳 CDN / 反代头;否则客户端可伪造这些头绕过 IP 维度的风控。
|
||||
$trusted = apply_filters('aksrt_trusted_proxies', []);
|
||||
if (is_array($trusted) && $trusted !== [] && $remote !== '' && !aksrt_ip_in_list($remote, $trusted)) {
|
||||
$trusted = apply_filters('jio_trusted_proxies', []);
|
||||
if (is_array($trusted) && $trusted !== [] && $remote !== '' && !jio_ip_in_list($remote, $trusted)) {
|
||||
return $remote;
|
||||
}
|
||||
|
||||
@@ -619,7 +619,7 @@ function aksrt_get_client_ip(): string {
|
||||
* @param string $ip 待判定 IP。
|
||||
* @param array $list 精确 IP / CIDR 段列表。
|
||||
*/
|
||||
function aksrt_ip_in_list(string $ip, array $list): bool {
|
||||
function jio_ip_in_list(string $ip, array $list): bool {
|
||||
foreach ($list as $entry) {
|
||||
$entry = trim((string) $entry);
|
||||
if ($entry === '') {
|
||||
@@ -659,9 +659,9 @@ function aksrt_ip_in_list(string $ip, array $list): bool {
|
||||
}
|
||||
|
||||
// Native wp-comments-post + any path that omits comment_author_IP.
|
||||
// Ensures comment_author_IP (and thus aksrt_comment_addr) is the real client IP behind CDN.
|
||||
// Ensures comment_author_IP (and thus jio_comment_addr) is the real client IP behind CDN.
|
||||
add_filter('pre_comment_user_ip', static function ($ip) {
|
||||
$resolved = aksrt_get_client_ip();
|
||||
$resolved = jio_get_client_ip();
|
||||
return ($resolved !== '' && $resolved !== '0.0.0.0') ? $resolved : $ip;
|
||||
}, 5);
|
||||
|
||||
@@ -669,7 +669,7 @@ add_filter('pre_comment_user_ip', static function ($ip) {
|
||||
// 腾讯云 API 3.0 TC3-HMAC-SHA256 签名
|
||||
// ============================================================
|
||||
|
||||
function aksrt_tencent_tc3_sign($secret_id, $secret_key, $service, $timestamp, $date, $action, $version, $payload): array {
|
||||
function jio_tencent_tc3_sign($secret_id, $secret_key, $service, $timestamp, $date, $action, $version, $payload): array {
|
||||
$content_type = 'application/json; charset=utf-8';
|
||||
$host = 'captcha.tencentcloudapi.com';
|
||||
$payload_hash = hash('sha256', $payload);
|
||||
@@ -703,7 +703,7 @@ function aksrt_tencent_tc3_sign($secret_id, $secret_key, $service, $timestamp, $
|
||||
/**
|
||||
* 阿里云 OpenAPI POP Signature v1.0 (HMAC-SHA1)。
|
||||
*/
|
||||
function aksrt_aliyun_afs_sign(array $params, string $secret): string {
|
||||
function jio_aliyun_afs_sign(array $params, string $secret): string {
|
||||
ksort($params);
|
||||
$canonicalized = '';
|
||||
foreach ($params as $k => $v) {
|
||||
@@ -720,11 +720,11 @@ function aksrt_aliyun_afs_sign(array $params, string $secret): string {
|
||||
/**
|
||||
* 记录传输层 / 厂商原始错误细节,供站点排查;对用户只暴露通用文案。
|
||||
*/
|
||||
function aksrt_captcha_log(string $provider, string $detail): void {
|
||||
error_log('[AKSRT Captcha] ' . $provider . ': ' . $detail);
|
||||
function jio_captcha_log(string $provider, string $detail): void {
|
||||
error_log('[Jio Captcha] ' . $provider . ': ' . $detail);
|
||||
}
|
||||
|
||||
function aksrt_captcha_error(string $code, string $message, array $data = []): \WP_Error {
|
||||
function jio_captcha_error(string $code, string $message, array $data = []): \WP_Error {
|
||||
return new \WP_Error($code, $message, $data);
|
||||
}
|
||||
|
||||
@@ -733,20 +733,20 @@ function aksrt_captcha_error(string $code, string $message, array $data = []): \
|
||||
*
|
||||
* @return array|\WP_Error
|
||||
*/
|
||||
function aksrt_captcha_remote_json(string $provider, $response) {
|
||||
function jio_captcha_remote_json(string $provider, $response) {
|
||||
if (is_wp_error($response)) {
|
||||
aksrt_captcha_log($provider, $response->get_error_message());
|
||||
return aksrt_captcha_error('aksrt_captcha_transport', __('人机验证服务暂不可用,请稍后重试', 'aksrt'));
|
||||
jio_captcha_log($provider, $response->get_error_message());
|
||||
return jio_captcha_error('jio_captcha_transport', __('人机验证服务暂不可用,请稍后重试', 'jio'));
|
||||
}
|
||||
$status = (int) wp_remote_retrieve_response_code($response);
|
||||
if ($status < 200 || $status >= 300) {
|
||||
aksrt_captcha_log($provider, 'HTTP ' . $status . ': ' . substr((string) wp_remote_retrieve_body($response), 0, 500));
|
||||
return aksrt_captcha_error('aksrt_captcha_http', __('人机验证服务暂不可用,请稍后重试', 'aksrt'), ['status' => $status]);
|
||||
jio_captcha_log($provider, 'HTTP ' . $status . ': ' . substr((string) wp_remote_retrieve_body($response), 0, 500));
|
||||
return jio_captcha_error('jio_captcha_http', __('人机验证服务暂不可用,请稍后重试', 'jio'), ['status' => $status]);
|
||||
}
|
||||
$body = json_decode(wp_remote_retrieve_body($response), true);
|
||||
if (!is_array($body)) {
|
||||
aksrt_captcha_log($provider, 'unparsable response');
|
||||
return aksrt_captcha_error('aksrt_captcha_response', __('人机验证服务暂不可用,请稍后重试', 'aksrt'));
|
||||
jio_captcha_log($provider, 'unparsable response');
|
||||
return jio_captcha_error('jio_captcha_response', __('人机验证服务暂不可用,请稍后重试', 'jio'));
|
||||
}
|
||||
return $body;
|
||||
}
|
||||
@@ -756,26 +756,26 @@ function aksrt_captcha_remote_json(string $provider, $response) {
|
||||
*
|
||||
* @return true|\WP_Error
|
||||
*/
|
||||
function aksrt_verify_captcha_provider(string $provider, array $pcfg, array $post_data, string $client_ip, string $scene = '', string $action = 'aksrt-verify') {
|
||||
if (!in_array($provider, aksrt_captcha_providers(), true)) {
|
||||
return aksrt_captcha_error('aksrt_captcha_provider', __('未知的人机验证服务商', 'aksrt'));
|
||||
function jio_verify_captcha_provider(string $provider, array $pcfg, array $post_data, string $client_ip, string $scene = '', string $action = 'jio-verify') {
|
||||
if (!in_array($provider, jio_captcha_providers(), true)) {
|
||||
return jio_captcha_error('jio_captcha_provider', __('未知的人机验证服务商', 'jio'));
|
||||
}
|
||||
if (!aksrt_captcha_provider_is_configured($provider, $pcfg)) {
|
||||
return aksrt_captcha_error('aksrt_captcha_config', __('验证码配置不完整', 'aksrt'));
|
||||
if (!jio_captcha_provider_is_configured($provider, $pcfg)) {
|
||||
return jio_captcha_error('jio_captcha_config', __('验证码配置不完整', 'jio'));
|
||||
}
|
||||
|
||||
switch ($provider) {
|
||||
case 'tencent':
|
||||
return aksrt_verify_tencent($pcfg, $post_data, $client_ip);
|
||||
return jio_verify_tencent($pcfg, $post_data, $client_ip);
|
||||
case 'cloudflare':
|
||||
return aksrt_verify_cloudflare($pcfg, $post_data, $client_ip, $scene, $action);
|
||||
return jio_verify_cloudflare($pcfg, $post_data, $client_ip, $scene, $action);
|
||||
case 'geetest':
|
||||
return aksrt_verify_geetest($pcfg, $post_data);
|
||||
return jio_verify_geetest($pcfg, $post_data);
|
||||
case 'aliyun':
|
||||
return aksrt_verify_aliyun($pcfg, $post_data);
|
||||
return jio_verify_aliyun($pcfg, $post_data);
|
||||
}
|
||||
|
||||
return aksrt_captcha_error('aksrt_captcha_provider', __('未知的人机验证服务商', 'aksrt'));
|
||||
return jio_captcha_error('jio_captcha_provider', __('未知的人机验证服务商', 'jio'));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -783,20 +783,20 @@ function aksrt_verify_captcha_provider(string $provider, array $pcfg, array $pos
|
||||
*
|
||||
* @return true|\WP_Error
|
||||
*/
|
||||
function aksrt_verify_tencent(array $pcfg, array $post_data, string $client_ip) {
|
||||
function jio_verify_tencent(array $pcfg, array $post_data, string $client_ip) {
|
||||
$ticket = (string) ($post_data['tencent_ticket'] ?? '');
|
||||
$randstr = (string) ($post_data['tencent_randstr'] ?? '');
|
||||
if ($ticket === '' || $randstr === '') {
|
||||
return aksrt_captcha_error('aksrt_captcha_missing', __('缺少验证参数', 'aksrt'));
|
||||
return jio_captcha_error('jio_captcha_missing', __('缺少验证参数', 'jio'));
|
||||
}
|
||||
if (str_starts_with($ticket, 'trerror_')) {
|
||||
return aksrt_captcha_error('aksrt_captcha_disaster_ticket', __('验证码 SDK 异常,请刷新页面重试(容灾票据)', 'aksrt'));
|
||||
return jio_captcha_error('jio_captcha_disaster_ticket', __('验证码 SDK 异常,请刷新页面重试(容灾票据)', 'jio'));
|
||||
}
|
||||
|
||||
$secret_id = (string) ($pcfg['secret_id'] ?? '');
|
||||
$secret_key = (string) ($pcfg['secret_key'] ?? '');
|
||||
if ($secret_id === '' || $secret_key === '') {
|
||||
return aksrt_captcha_error('aksrt_captcha_config', __('验证码配置不完整:缺少云 API 密钥 (SecretId/SecretKey)', 'aksrt'));
|
||||
return jio_captcha_error('jio_captcha_config', __('验证码配置不完整:缺少云 API 密钥 (SecretId/SecretKey)', 'jio'));
|
||||
}
|
||||
|
||||
$timestamp = time();
|
||||
@@ -810,21 +810,21 @@ function aksrt_verify_tencent(array $pcfg, array $post_data, string $client_ip)
|
||||
'UserIp' => $client_ip,
|
||||
]);
|
||||
|
||||
$headers = aksrt_tencent_tc3_sign($secret_id, $secret_key, 'captcha', $timestamp, $date, 'DescribeCaptchaResult', '2019-07-22', $payload);
|
||||
$headers = jio_tencent_tc3_sign($secret_id, $secret_key, 'captcha', $timestamp, $date, 'DescribeCaptchaResult', '2019-07-22', $payload);
|
||||
|
||||
$resp = wp_remote_post('https://captcha.tencentcloudapi.com/', [
|
||||
'timeout' => 5,
|
||||
'headers' => $headers,
|
||||
'body' => $payload,
|
||||
]);
|
||||
$body = aksrt_captcha_remote_json('tencent', $resp);
|
||||
$body = jio_captcha_remote_json('tencent', $resp);
|
||||
if (is_wp_error($body)) {
|
||||
return $body;
|
||||
}
|
||||
if (isset($body['Response']['Error'])) {
|
||||
$err = $body['Response']['Error'];
|
||||
aksrt_captcha_log('tencent', ($err['Code'] ?? 'unknown') . ': ' . ($err['Message'] ?? ''));
|
||||
return aksrt_captcha_error('aksrt_captcha_provider_error', __('人机验证服务暂不可用,请稍后重试', 'aksrt'));
|
||||
jio_captcha_log('tencent', ($err['Code'] ?? 'unknown') . ': ' . ($err['Message'] ?? ''));
|
||||
return jio_captcha_error('jio_captcha_provider_error', __('人机验证服务暂不可用,请稍后重试', 'jio'));
|
||||
}
|
||||
|
||||
$resp_data = $body['Response'] ?? [];
|
||||
@@ -844,8 +844,8 @@ function aksrt_verify_tencent(array $pcfg, array $post_data, string $client_ip)
|
||||
100 => '参数校验失败(AppId/SecretKey/Ticket 不匹配)',
|
||||
];
|
||||
$msg = (string) ($resp_data['CaptchaMsg'] ?? ($messages[$captcha_code] ?? '未知错误'));
|
||||
aksrt_captcha_log('tencent', $msg . " (CaptchaCode: {$captcha_code})");
|
||||
return aksrt_captcha_error('aksrt_captcha_rejected', __('人机验证未通过,请重试', 'aksrt'));
|
||||
jio_captcha_log('tencent', $msg . " (CaptchaCode: {$captcha_code})");
|
||||
return jio_captcha_error('jio_captcha_rejected', __('人机验证未通过,请重试', 'jio'));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -853,10 +853,10 @@ function aksrt_verify_tencent(array $pcfg, array $post_data, string $client_ip)
|
||||
*
|
||||
* @return true|\WP_Error
|
||||
*/
|
||||
function aksrt_verify_cloudflare(array $pcfg, array $post_data, string $client_ip, string $scene = '', string $action = 'aksrt-verify') {
|
||||
function jio_verify_cloudflare(array $pcfg, array $post_data, string $client_ip, string $scene = '', string $action = 'jio-verify') {
|
||||
$token = (string) ($post_data['cf_turnstile_response'] ?? '');
|
||||
if ($token === '' || strlen($token) < 10) {
|
||||
return aksrt_captcha_error('aksrt_captcha_missing', __('缺少验证参数', 'aksrt'));
|
||||
return jio_captcha_error('jio_captcha_missing', __('缺少验证参数', 'jio'));
|
||||
}
|
||||
|
||||
$resp = wp_remote_post('https://challenges.cloudflare.com/turnstile/v0/siteverify', [
|
||||
@@ -867,29 +867,29 @@ function aksrt_verify_cloudflare(array $pcfg, array $post_data, string $client_i
|
||||
'remoteip' => $client_ip,
|
||||
],
|
||||
]);
|
||||
$body = aksrt_captcha_remote_json('cloudflare', $resp);
|
||||
$body = jio_captcha_remote_json('cloudflare', $resp);
|
||||
if (is_wp_error($body)) {
|
||||
return $body;
|
||||
}
|
||||
if (empty($body['success'])) {
|
||||
aksrt_captcha_log('cloudflare', 'siteverify failed: ' . implode(', ', (array) ($body['error-codes'] ?? [])));
|
||||
return aksrt_captcha_error('aksrt_captcha_rejected', __('人机验证未通过,请重试', 'aksrt'));
|
||||
jio_captcha_log('cloudflare', 'siteverify failed: ' . implode(', ', (array) ($body['error-codes'] ?? [])));
|
||||
return jio_captcha_error('jio_captcha_rejected', __('人机验证未通过,请重试', 'jio'));
|
||||
}
|
||||
|
||||
if (!array_key_exists('action', $body) || (string) $body['action'] !== $action) {
|
||||
aksrt_captcha_log('cloudflare', 'action mismatch: ' . (string) ($body['action'] ?? '<missing>') . ' != ' . $action);
|
||||
return aksrt_captcha_error('aksrt_captcha_action', __('人机验证未通过,请重试', 'aksrt'));
|
||||
jio_captcha_log('cloudflare', 'action mismatch: ' . (string) ($body['action'] ?? '<missing>') . ' != ' . $action);
|
||||
return jio_captcha_error('jio_captcha_action', __('人机验证未通过,请重试', 'jio'));
|
||||
}
|
||||
if (!array_key_exists('cdata', $body) || (string) $body['cdata'] !== $scene) {
|
||||
aksrt_captcha_log('cloudflare', 'cdata mismatch: ' . (string) ($body['cdata'] ?? '<missing>') . ' != ' . $scene);
|
||||
return aksrt_captcha_error('aksrt_captcha_cdata', __('人机验证未通过,请重试', 'aksrt'));
|
||||
jio_captcha_log('cloudflare', 'cdata mismatch: ' . (string) ($body['cdata'] ?? '<missing>') . ' != ' . $scene);
|
||||
return jio_captcha_error('jio_captcha_cdata', __('人机验证未通过,请重试', 'jio'));
|
||||
}
|
||||
|
||||
$expected_host = strtolower((string) wp_parse_url(home_url('/'), PHP_URL_HOST));
|
||||
$response_host = strtolower(trim((string) ($body['hostname'] ?? '')));
|
||||
if ($expected_host === '' || $response_host === '' || !hash_equals($expected_host, $response_host)) {
|
||||
aksrt_captcha_log('cloudflare', 'hostname mismatch: ' . ($response_host ?: '<missing>') . ' != ' . ($expected_host ?: '<missing>'));
|
||||
return aksrt_captcha_error('aksrt_captcha_hostname', __('人机验证未通过,请重试', 'aksrt'));
|
||||
jio_captcha_log('cloudflare', 'hostname mismatch: ' . ($response_host ?: '<missing>') . ' != ' . ($expected_host ?: '<missing>'));
|
||||
return jio_captcha_error('jio_captcha_hostname', __('人机验证未通过,请重试', 'jio'));
|
||||
}
|
||||
|
||||
return true;
|
||||
@@ -900,13 +900,13 @@ function aksrt_verify_cloudflare(array $pcfg, array $post_data, string $client_i
|
||||
*
|
||||
* @return true|\WP_Error
|
||||
*/
|
||||
function aksrt_verify_geetest(array $pcfg, array $post_data) {
|
||||
function jio_verify_geetest(array $pcfg, array $post_data) {
|
||||
$lot_number = (string) ($post_data['geetest_lot_number'] ?? '');
|
||||
$captcha_output = (string) ($post_data['geetest_captcha_output'] ?? '');
|
||||
$pass_token = (string) ($post_data['geetest_pass_token'] ?? '');
|
||||
$gen_time = (string) ($post_data['geetest_gen_time'] ?? '');
|
||||
if ($lot_number === '' || $captcha_output === '' || $pass_token === '') {
|
||||
return aksrt_captcha_error('aksrt_captcha_missing', __('缺少验证参数', 'aksrt'));
|
||||
return jio_captcha_error('jio_captcha_missing', __('缺少验证参数', 'jio'));
|
||||
}
|
||||
|
||||
$captcha_key = (string) ($pcfg['captcha_key'] ?? '');
|
||||
@@ -924,15 +924,15 @@ function aksrt_verify_geetest(array $pcfg, array $post_data) {
|
||||
],
|
||||
]);
|
||||
|
||||
$body = aksrt_captcha_remote_json('geetest', $resp);
|
||||
$body = jio_captcha_remote_json('geetest', $resp);
|
||||
if (is_wp_error($body)) {
|
||||
return $body;
|
||||
}
|
||||
if (($body['result'] ?? '') === 'success') {
|
||||
return true;
|
||||
}
|
||||
aksrt_captcha_log('geetest', 'validate failed: ' . (string) ($body['reason'] ?? ($body['msg'] ?? 'unknown')));
|
||||
return aksrt_captcha_error('aksrt_captcha_rejected', __('人机验证未通过,请重试', 'aksrt'));
|
||||
jio_captcha_log('geetest', 'validate failed: ' . (string) ($body['reason'] ?? ($body['msg'] ?? 'unknown')));
|
||||
return jio_captcha_error('jio_captcha_rejected', __('人机验证未通过,请重试', 'jio'));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -940,10 +940,10 @@ function aksrt_verify_geetest(array $pcfg, array $post_data) {
|
||||
*
|
||||
* @return true|\WP_Error
|
||||
*/
|
||||
function aksrt_verify_aliyun(array $pcfg, array $post_data) {
|
||||
function jio_verify_aliyun(array $pcfg, array $post_data) {
|
||||
$captcha_verify_param = (string) ($post_data['aliyun_captcha_verify_param'] ?? '');
|
||||
if ($captcha_verify_param === '') {
|
||||
return aksrt_captcha_error('aksrt_captcha_missing', __('缺少验证参数 (captchaVerifyParam)', 'aksrt'));
|
||||
return jio_captcha_error('jio_captcha_missing', __('缺少验证参数 (captchaVerifyParam)', 'jio'));
|
||||
}
|
||||
|
||||
$region = (string) ($pcfg['region'] ?? 'cn');
|
||||
@@ -965,14 +965,14 @@ function aksrt_verify_aliyun(array $pcfg, array $post_data) {
|
||||
if (!empty($pcfg['scene_id'])) {
|
||||
$params['SceneId'] = (string) $pcfg['scene_id'];
|
||||
}
|
||||
$params['Signature'] = aksrt_aliyun_afs_sign($params, (string) ($pcfg['access_key_secret'] ?? ''));
|
||||
$params['Signature'] = jio_aliyun_afs_sign($params, (string) ($pcfg['access_key_secret'] ?? ''));
|
||||
|
||||
$resp = wp_remote_post('https://' . $endpoint . '/', [
|
||||
'timeout' => 5,
|
||||
'body' => $params,
|
||||
]);
|
||||
|
||||
$body = aksrt_captcha_remote_json('aliyun', $resp);
|
||||
$body = jio_captcha_remote_json('aliyun', $resp);
|
||||
if (is_wp_error($body)) {
|
||||
return $body;
|
||||
}
|
||||
@@ -1001,12 +1001,12 @@ function aksrt_verify_aliyun(array $pcfg, array $post_data) {
|
||||
];
|
||||
$verify_code = (string) ($body['Result']['VerifyCode'] ?? '');
|
||||
$detail = $code_messages[$verify_code] ?? '未知错误 (' . ($verify_code ?: 'N/A') . ')';
|
||||
aksrt_captcha_log('aliyun', 'verify rejected: ' . $detail);
|
||||
return aksrt_captcha_error('aksrt_captcha_rejected', __('人机验证未通过,请重试', 'aksrt'));
|
||||
jio_captcha_log('aliyun', 'verify rejected: ' . $detail);
|
||||
return jio_captcha_error('jio_captcha_rejected', __('人机验证未通过,请重试', 'jio'));
|
||||
}
|
||||
|
||||
aksrt_captcha_log('aliyun', 'api failed: ' . (string) ($body['Message'] ?? 'unknown'));
|
||||
return aksrt_captcha_error('aksrt_captcha_provider_error', __('人机验证服务暂不可用,请稍后重试', 'aksrt'));
|
||||
jio_captcha_log('aliyun', 'api failed: ' . (string) ($body['Message'] ?? 'unknown'));
|
||||
return jio_captcha_error('jio_captcha_provider_error', __('人机验证服务暂不可用,请稍后重试', 'jio'));
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
@@ -1018,22 +1018,22 @@ function aksrt_verify_aliyun(array $pcfg, array $post_data) {
|
||||
*
|
||||
* 挂载点自带 JSON 配置,由 captcha-front.js(public bundle)扫描激活。
|
||||
*/
|
||||
function aksrt_render_captcha($scene = 'comment') {
|
||||
function jio_render_captcha($scene = 'comment') {
|
||||
$scene = sanitize_key((string) $scene);
|
||||
if (!aksrt_is_captcha_enabled_for($scene)) {
|
||||
if (!jio_is_captcha_enabled_for($scene)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$cfg = aksrt_get_captcha_config();
|
||||
$cfg = jio_get_captcha_config();
|
||||
$provider = $cfg['active_provider'];
|
||||
$pcfg = $cfg[$provider] ?? [];
|
||||
|
||||
if (!aksrt_captcha_provider_is_configured($provider, $pcfg)) {
|
||||
if (!jio_captcha_provider_is_configured($provider, $pcfg)) {
|
||||
if (current_user_can('manage_options')) {
|
||||
echo '<div class="aksrt-captcha-misconfig" style="font-size:12px;color:#d03050;margin:8px 0;">';
|
||||
echo '<div class="jio-captcha-misconfig" style="font-size:12px;color:#d03050;margin:8px 0;">';
|
||||
echo esc_html(sprintf(
|
||||
/* translators: %s: captcha provider key */
|
||||
__('人机验证服务商「%s」已启用但凭据未配齐,当前场景将拒绝提交。请到「功能&权限 → 人机验证」补全配置。', 'aksrt'),
|
||||
__('人机验证服务商「%s」已启用但凭据未配齐,当前场景将拒绝提交。请到「功能&权限 → 人机验证」补全配置。', 'jio'),
|
||||
$provider
|
||||
));
|
||||
echo '</div>';
|
||||
@@ -1041,7 +1041,7 @@ function aksrt_render_captcha($scene = 'comment') {
|
||||
return;
|
||||
}
|
||||
|
||||
$uid = 'aksrt-captcha-' . $scene . '-' . wp_unique_id();
|
||||
$uid = 'jio-captcha-' . $scene . '-' . wp_unique_id();
|
||||
$vid = 'captcha_verified_' . $scene . '_' . wp_unique_id();
|
||||
|
||||
$js_config = [
|
||||
@@ -1049,8 +1049,8 @@ function aksrt_render_captcha($scene = 'comment') {
|
||||
'scene' => $scene,
|
||||
'uid' => $uid,
|
||||
'vid' => $vid,
|
||||
'challenge_url' => rest_url('aksrt/v1/captcha/challenge'),
|
||||
'exchange_url' => rest_url('aksrt/v1/captcha/exchange'),
|
||||
'challenge_url' => rest_url('jio/v1/captcha/challenge'),
|
||||
'exchange_url' => rest_url('jio/v1/captcha/exchange'),
|
||||
'tc' => ['app_id' => (string) ($pcfg['app_id'] ?? '')],
|
||||
'cf' => [
|
||||
'site_key' => (string) ($pcfg['site_key'] ?? ''),
|
||||
@@ -1068,11 +1068,11 @@ function aksrt_render_captcha($scene = 'comment') {
|
||||
],
|
||||
];
|
||||
?>
|
||||
<div class="aksrt-captcha-wrap" data-provider="<?php echo esc_attr($provider); ?>" data-scene="<?php echo esc_attr($scene); ?>" data-aksrt-captcha-config="<?php echo esc_attr(wp_json_encode($js_config, JSON_UNESCAPED_UNICODE)); ?>">
|
||||
<div id="<?php echo esc_attr($uid); ?>" class="aksrt-captcha-box" style="display:none"></div>
|
||||
<div class="jio-captcha-wrap" data-provider="<?php echo esc_attr($provider); ?>" data-scene="<?php echo esc_attr($scene); ?>" data-jio-captcha-config="<?php echo esc_attr(wp_json_encode($js_config, JSON_UNESCAPED_UNICODE)); ?>">
|
||||
<div id="<?php echo esc_attr($uid); ?>" class="jio-captcha-box" style="display:none"></div>
|
||||
<input type="hidden" name="captcha_verified" id="<?php echo esc_attr($vid); ?>" value="0">
|
||||
<input type="hidden" name="aksrt_captcha_challenge" value="">
|
||||
<input type="hidden" name="aksrt_captcha_proof" value="">
|
||||
<input type="hidden" name="jio_captcha_challenge" value="">
|
||||
<input type="hidden" name="jio_captcha_proof" value="">
|
||||
</div>
|
||||
<?php
|
||||
}
|
||||
Reference in new issue
Block a user