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:
kate522andClaude Opus 5 committed 2026-11-01 20:05:04 +08:00
1 parent 5b16bc6e15
commit 35bb96e82f
997 files changed
+28216 -28188

No files matched your search

+47 -47
View File
@@ -2,21 +2,21 @@
/**
* WeChat Official Account QR and verification-code authentication.
*
* @package AKSRT
* @package Jio
*/
namespace AKSRT\Auth;
namespace Jio\Auth;
use AKSRT\Settings\Settings;
use Jio\Settings\Settings;
defined('ABSPATH') || exit;
final class WeixinGzh {
private const ACCESS_OPTION = 'aksrt_weixingzh_access_token';
private const SCENE_OPTION_PREFIX = 'aksrt_weixingzh_scene_';
private const CODE_OPTION_PREFIX = 'aksrt_weixingzh_code_';
private const DEDUPE_OPTION_PREFIX = 'aksrt_weixingzh_event_';
private const ACCESS_OPTION = 'jio_weixingzh_access_token';
private const SCENE_OPTION_PREFIX = 'jio_weixingzh_scene_';
private const CODE_OPTION_PREFIX = 'jio_weixingzh_code_';
private const DEDUPE_OPTION_PREFIX = 'jio_weixingzh_event_';
private const SCAN_KIND = 'weixingzh_scan';
private const CODE_KIND = 'weixingzh_code';
private const SCAN_TTL = 5 * MINUTE_IN_SECONDS;
@@ -42,17 +42,17 @@ final class WeixinGzh {
}
public function register_routes(): void {
register_rest_route('aksrt/v1', '/auth/qrcode-login', [
register_rest_route('jio/v1', '/auth/qrcode-login', [
'methods' => ['GET', 'POST'],
'callback' => [$this, 'rest_qrcode_login'],
'permission_callback' => '__return_true',
]);
register_rest_route('aksrt/v1', '/auth/check-qrcode-login', [
register_rest_route('jio/v1', '/auth/check-qrcode-login', [
'methods' => ['GET', 'POST'],
'callback' => [$this, 'rest_check_qrcode_login'],
'permission_callback' => '__return_true',
]);
register_rest_route('aksrt/v1', '/auth/weixingzh-code', [
register_rest_route('jio/v1', '/auth/weixingzh-code', [
'methods' => 'POST',
'callback' => [$this, 'rest_code_login'],
'permission_callback' => '__return_true',
@@ -96,7 +96,7 @@ final class WeixinGzh {
return $limited;
}
if (!self::is_enabled()) {
return $this->error_response(__('微信公众号登录未开启或配置不完整', 'aksrt'), 400);
return $this->error_response(__('微信公众号登录未开启或配置不完整', 'jio'), 400);
}
$context = $this->request_context($request);
if (is_wp_error($context)) {
@@ -108,7 +108,7 @@ final class WeixinGzh {
$data = $this->request_data($request);
$bind_pass = sanitize_text_field((string) ($data['bind_pass'] ?? ''));
if (!OAuth::validate_bind_pass($bind_pass, 'weixingzh', $context['user_id'], false)) {
return $this->error_response(__('请先完成人机验证后再绑定', 'aksrt'), 403);
return $this->error_response(__('请先完成人机验证后再绑定', 'jio'), 403);
}
$context['bind_pass'] = $bind_pass;
}
@@ -118,7 +118,7 @@ final class WeixinGzh {
$appid = trim((string) ($config['appid'] ?? ''));
$secret = trim((string) ($config['appsecret'] ?? ''));
$scene = 'aksrt_' . rtrim(strtr(base64_encode(random_bytes(18)), '+/', '-_'), '=');
$scene = 'jio_' . rtrim(strtr(base64_encode(random_bytes(18)), '+/', '-_'), '=');
$transaction = '';
try {
$transaction = OAuthTransactionStore::issue(self::SCAN_KIND, [
@@ -147,8 +147,8 @@ final class WeixinGzh {
throw new \RuntimeException((string) ($created['errmsg'] ?? 'qrcode_create_failed'));
}
$image = 'https://mp.weixin.qq.com/cgi-bin/showqrcode?ticket=' . rawurlencode((string) $created['ticket']);
$html = '<img class="signin-qrcode-img" src="' . esc_url($image) . '" alt="' . esc_attr__('微信公众号扫码登录二维码', 'aksrt') . '" style="width:160px;height:160px;" />';
$html .= '<p class="text-center mt10 em09 muted-2-color"><i class="fa fab fa-weixin c-green"></i> ' . esc_html__('微信扫码登录', 'aksrt') . '</p>';
$html = '<img class="signin-qrcode-img" src="' . esc_url($image) . '" alt="' . esc_attr__('微信公众号扫码登录二维码', 'jio') . '" style="width:160px;height:160px;" />';
$html .= '<p class="text-center mt10 em09 muted-2-color"><i class="fa fab fa-weixin c-green"></i> ' . esc_html__('微信扫码登录', 'jio') . '</p>';
return new \WP_REST_Response([
'success' => true,
'data' => [
@@ -164,7 +164,7 @@ final class WeixinGzh {
OAuthTransactionStore::delete($transaction);
$this->delete_scene_mapping($scene, $transaction);
}
return $this->error_response(__('创建微信登录二维码失败,请稍后重试', 'aksrt'), 502);
return $this->error_response(__('创建微信登录二维码失败,请稍后重试', 'jio'), 502);
}
}
@@ -174,12 +174,12 @@ final class WeixinGzh {
return $limited;
}
if (!self::is_enabled()) {
return $this->error_response(__('微信公众号登录未开启或配置不完整', 'aksrt'), 400);
return $this->error_response(__('微信公众号登录未开启或配置不完整', 'jio'), 400);
}
$data = $this->request_data($request);
$token = sanitize_text_field((string) ($data['token'] ?? ''));
if ($token === '') {
return $this->error_response(__('缺少 token', 'aksrt'), 400);
return $this->error_response(__('缺少 token', 'jio'), 400);
}
$row = OAuthTransactionStore::peek($token, self::SCAN_KIND, true);
if (!$row) {
@@ -194,7 +194,7 @@ final class WeixinGzh {
], 200);
}
if (!$this->binding_user_matches($payload)) {
return $this->error_response(__('绑定会话与当前用户不匹配', 'aksrt'), 403);
return $this->error_response(__('绑定会话与当前用户不匹配', 'jio'), 403);
}
$claimed = OAuthTransactionStore::claim($token, self::SCAN_KIND, true);
if (!$claimed) {
@@ -210,12 +210,12 @@ final class WeixinGzh {
return $limited;
}
if (!self::is_enabled()) {
return $this->error_response(__('微信公众号登录未开启或配置不完整', 'aksrt'), 400);
return $this->error_response(__('微信公众号登录未开启或配置不完整', 'jio'), 400);
}
$data = $this->request_data($request);
$code = strtoupper(sanitize_text_field((string) ($data['code'] ?? '')));
if (preg_match('/^[A-Z0-9]{6,12}$/', $code) !== 1) {
return $this->error_response(__('请输入至少 6 位的有效验证码', 'aksrt'), 400);
return $this->error_response(__('请输入至少 6 位的有效验证码', 'jio'), 400);
}
$context = $this->request_context($request);
if (is_wp_error($context)) {
@@ -225,12 +225,12 @@ final class WeixinGzh {
if ($context['action'] === 'bind') {
$bind_pass = sanitize_text_field((string) ($data['bind_pass'] ?? ''));
if (!OAuth::validate_bind_pass($bind_pass, 'weixingzh', $context['user_id'], false)) {
return $this->error_response(__('请先完成人机验证后再绑定', 'aksrt'), 403);
return $this->error_response(__('请先完成人机验证后再绑定', 'jio'), 403);
}
}
$claimed = $this->claim_code_transaction($code, $context);
if (!$claimed) {
return $this->error_response(__('验证码无效、已过期或尝试次数过多', 'aksrt'), 400);
return $this->error_response(__('验证码无效、已过期或尝试次数过多', 'jio'), 400);
}
$payload = is_array($claimed['payload'] ?? null) ? $claimed['payload'] : [];
if ($context['action'] === 'bind') {
@@ -243,7 +243,7 @@ final class WeixinGzh {
* WeChat server URL verification.
*/
public function maybe_server_verify(): void {
if (empty($_GET['aksrt_weixingzh']) || ($_SERVER['REQUEST_METHOD'] ?? '') !== 'GET' || !isset($_GET['echostr'])) {
if (empty($_GET['jio_weixingzh']) || ($_SERVER['REQUEST_METHOD'] ?? '') !== 'GET' || !isset($_GET['echostr'])) {
return;
}
if (!self::is_enabled() || !$this->verify_webhook_signature()) {
@@ -264,7 +264,7 @@ final class WeixinGzh {
* Receive plaintext WeChat server messages.
*/
public function maybe_server_message(): void {
if (empty($_GET['aksrt_weixingzh']) || ($_SERVER['REQUEST_METHOD'] ?? '') !== 'POST' || isset($_GET['echostr'])) {
if (empty($_GET['jio_weixingzh']) || ($_SERVER['REQUEST_METHOD'] ?? '') !== 'POST' || isset($_GET['echostr'])) {
return;
}
if (!self::is_enabled() || !$this->verify_webhook_signature()) {
@@ -312,18 +312,18 @@ final class WeixinGzh {
*/
private function code_mode_response(array $config, array $context): \WP_REST_Response {
$qr = trim((string) ($config['code_qrcode'] ?? ''));
$keyword = trim((string) ($config['code_keyword'] ?? __('登录', 'aksrt')));
$html = '<img class="signin-qrcode-img" src="' . esc_url($qr) . '" alt="' . esc_attr__('微信公众号验证码登录二维码', 'aksrt') . '" style="width:160px;height:160px;object-fit:contain;" />';
$html .= '<form class="aksrt-weixingzh-code-form" data-aksrt-weixingzh-code>';
$html .= '<p class="muted-2-color em09">' . esc_html(sprintf(__('关注公众号后发送「%s」获取验证码', 'aksrt'), $keyword)) . '</p>';
$keyword = trim((string) ($config['code_keyword'] ?? __('登录', 'jio')));
$html = '<img class="signin-qrcode-img" src="' . esc_url($qr) . '" alt="' . esc_attr__('微信公众号验证码登录二维码', 'jio') . '" style="width:160px;height:160px;object-fit:contain;" />';
$html .= '<form class="jio-weixingzh-code-form" data-jio-weixingzh-code>';
$html .= '<p class="muted-2-color em09">' . esc_html(sprintf(__('关注公众号后发送「%s」获取验证码', 'jio'), $keyword)) . '</p>';
$html .= '<input type="hidden" name="action" value="' . esc_attr($context['action']) . '" />';
$html .= '<input type="hidden" name="user_id" value="' . esc_attr((string) $context['user_id']) . '" />';
$html .= '<input type="hidden" name="redirect_to" value="' . esc_attr($context['redirect_to']) . '" />';
if (!empty($context['bind_pass'])) {
$html .= '<input type="hidden" name="bind_pass" value="' . esc_attr((string) $context['bind_pass']) . '" />';
}
$html .= '<input type="text" name="code" class="form-control" minlength="6" maxlength="12" autocomplete="one-time-code" placeholder="' . esc_attr__('请输入验证码', 'aksrt') . '" required />';
$html .= '<button type="submit" class="but c-blue btn-block mt10">' . esc_html__('登录', 'aksrt') . '</button>';
$html .= '<input type="text" name="code" class="form-control" minlength="6" maxlength="12" autocomplete="one-time-code" placeholder="' . esc_attr__('请输入验证码', 'jio') . '" required />';
$html .= '<button type="submit" class="but c-blue btn-block mt10">' . esc_html__('登录', 'jio') . '</button>';
$html .= '</form>';
return new \WP_REST_Response([
'success' => true,
@@ -341,10 +341,10 @@ final class WeixinGzh {
$requested_user_id = isset($data['user_id']) ? (int) $data['user_id'] : 0;
if ($action === 'bind') {
if ($current_user_id <= 0) {
return new \WP_Error('weixingzh_bind_login_required', __('请先登录后再绑定微信公众号', 'aksrt'));
return new \WP_Error('weixingzh_bind_login_required', __('请先登录后再绑定微信公众号', 'jio'));
}
if ($requested_user_id > 0 && $requested_user_id !== $current_user_id) {
return new \WP_Error('weixingzh_bind_user_mismatch', __('绑定请求与当前用户不匹配', 'aksrt'));
return new \WP_Error('weixingzh_bind_user_mismatch', __('绑定请求与当前用户不匹配', 'jio'));
}
}
$redirect = OAuthUrlPolicy::validated_redirect((string) ($data['redirect_to'] ?? ''), home_url('/'));
@@ -381,7 +381,7 @@ final class WeixinGzh {
private function complete_browser_identity(array $payload): \WP_REST_Response {
$openid = trim((string) ($payload['openid'] ?? ''));
if ($openid === '') {
return $this->error_response(__('微信身份信息无效', 'aksrt'), 400);
return $this->error_response(__('微信身份信息无效', 'jio'), 400);
}
$profile = is_array($payload['profile'] ?? null) ? $payload['profile'] : [];
$identity = [
@@ -395,17 +395,17 @@ final class WeixinGzh {
];
if ((string) ($payload['action'] ?? 'login') === 'bind') {
if (!$this->binding_user_matches($payload)) {
return $this->error_response(__('绑定会话与当前用户不匹配', 'aksrt'), 403);
return $this->error_response(__('绑定会话与当前用户不匹配', 'jio'), 403);
}
$bind_pass = sanitize_text_field((string) ($payload['bind_pass'] ?? ''));
if (!OAuth::validate_bind_pass($bind_pass, 'weixingzh', get_current_user_id(), true)) {
return $this->error_response(__('绑定验证已过期,请重新完成人机验证', 'aksrt'), 403);
return $this->error_response(__('绑定验证已过期,请重新完成人机验证', 'jio'), 403);
}
$result = OAuthAccountService::bind(get_current_user_id(), 'weixingzh', $identity);
if (is_wp_error($result)) {
return $this->error_response($result->get_error_message(), 409);
}
$redirect = function_exists('aksrt_get_user_center_url') ? aksrt_get_user_center_url('settings') : home_url('/');
$redirect = function_exists('jio_get_user_center_url') ? jio_get_user_center_url('settings') : home_url('/');
$redirect = add_query_arg(['oauth_action' => 'bind', 'oauth_provider' => 'weixingzh'], $redirect);
return new \WP_REST_Response([
'success' => true,
@@ -423,8 +423,8 @@ final class WeixinGzh {
'user_data' => $identity,
'redirect_to' => $redirect,
], 15 * MINUTE_IN_SECONDS, true);
$bind_url = function_exists('aksrt_get_bind_url')
? aksrt_get_bind_url($obk)
$bind_url = function_exists('jio_get_bind_url')
? jio_get_bind_url($obk)
: add_query_arg(['tab' => 'bind', 'obk' => $obk], home_url('/sign/'));
return new \WP_REST_Response([
'success' => true,
@@ -436,11 +436,11 @@ final class WeixinGzh {
],
], 200);
} catch (\Throwable $e) {
return $this->error_response(__('无法创建账号绑定会话,请重试', 'aksrt'), 500);
return $this->error_response(__('无法创建账号绑定会话,请重试', 'jio'), 500);
}
}
if (!$user instanceof \WP_User) {
return $this->error_response(is_wp_error($user) ? $user->get_error_message() : __('微信账号匹配失败', 'aksrt'), 400);
return $this->error_response(is_wp_error($user) ? $user->get_error_message() : __('微信账号匹配失败', 'jio'), 400);
}
OAuthAccountService::complete_login($user, true);
$redirect = OAuthUrlPolicy::validated_redirect((string) ($payload['redirect_to'] ?? ''), home_url('/'));
@@ -500,7 +500,7 @@ final class WeixinGzh {
$code = $this->issue_code($from);
$template = trim((string) ($config['code_reply'] ?? ''));
if ($template === '') {
$template = __('您的验证码是:%s,有效期 %d 分钟。', 'aksrt');
$template = __('您的验证码是:%s,有效期 %d 分钟。', 'jio');
}
$message = str_replace(['%code%', '%time%', '%s', '%d'], [$code, '5', $code, '5'], $template);
$this->echo_text_reply($from, $to, $message);
@@ -854,14 +854,14 @@ final class WeixinGzh {
}
private function rate_limit(string $scope, int $max, int $window, int $minimum_interval): ?\WP_REST_Response {
$ip = function_exists('aksrt_get_client_ip')
? trim((string) aksrt_get_client_ip())
$ip = function_exists('jio_get_client_ip')
? trim((string) jio_get_client_ip())
: trim((string) ($_SERVER['REMOTE_ADDR'] ?? 'unknown'));
$key = 'aksrt_weixingzh_rate_' . hash('sha256', $scope . '|' . $ip);
$key = 'jio_weixingzh_rate_' . hash('sha256', $scope . '|' . $ip);
$lock_scope = 'weixingzh-rate:' . $key;
$lock = OAuthTransactionStore::acquire_lock($lock_scope, 5);
if ($lock === false) {
return $this->error_response(__('请求过于频繁,请稍后重试', 'aksrt'), 429);
return $this->error_response(__('请求过于频繁,请稍后重试', 'jio'), 429);
}
try {
$now = time();
@@ -871,7 +871,7 @@ final class WeixinGzh {
}
$last_at = (float) ($row['last_at'] ?? 0);
if ((int) ($row['count'] ?? 0) >= $max || microtime(true) - $last_at < $minimum_interval) {
return $this->error_response(__('请求过于频繁,请稍后重试', 'aksrt'), 429);
return $this->error_response(__('请求过于频繁,请稍后重试', 'jio'), 429);
}
$row['count'] = (int) $row['count'] + 1;
$row['last_at'] = microtime(true);