From 3675b7dcef5c9de27c745fd7c60e97cd4932d789 Mon Sep 17 00:00:00 2001 From: unknown Date: Sun, 12 Jul 2026 14:35:19 +0800 Subject: [PATCH] =?UTF-8?q?fix(extensions):=20IP=20=E5=BD=92=E5=B1=9E?= =?UTF-8?q?=E5=9C=B0=E7=AE=A1=E7=90=86=E7=AB=AF=E6=B5=8B=E8=AF=95=E5=8F=AF?= =?UTF-8?q?=E7=BB=95=E8=BF=87=E5=90=AF=E7=94=A8=E5=BC=80=E5=85=B3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 后台测试此前受 ip_geo_enabled 短路,未启用时结果恒为空;强制 live lookup 并返回可读失败原因。 --- assets/admin/src/api/modules/extensions.js | 4 +- .../pages/extensions/ExtensionSecurity.vue | 12 ++++-- ...class-aksrt-admin-extension-controller.php | 43 +++++++++++++++++-- inc/classes/class-aksrt-ip-geo.php | 40 +++++++++++------ 4 files changed, 78 insertions(+), 21 deletions(-) diff --git a/assets/admin/src/api/modules/extensions.js b/assets/admin/src/api/modules/extensions.js index 590a5440..5765f40c 100644 --- a/assets/admin/src/api/modules/extensions.js +++ b/assets/admin/src/api/modules/extensions.js @@ -3,8 +3,8 @@ export const extensionsApiMethods = { * 扩展&增强 (Extensions) * ================================================================ */ - testIpGeo(ip) { return this.request('/extensions/ip-test', { method: 'POST', body: JSON.stringify({ ip }) }) }, - testContentAudit(text) { return this.request('/extensions/audit-test', { method: 'POST', body: JSON.stringify({ text }) }) }, + testIpGeo(ip) { return this.request('/extensions/ip-test', { method: 'POST', data: { ip } }) }, + testContentAudit(text) { return this.request('/extensions/audit-test', { method: 'POST', data: { text } }) }, /* AI 辅助(兼容页) */ getAiStatus() { return this.request('/ai/status') }, diff --git a/assets/admin/src/pages/extensions/ExtensionSecurity.vue b/assets/admin/src/pages/extensions/ExtensionSecurity.vue index 657d2c2e..d6206433 100644 --- a/assets/admin/src/pages/extensions/ExtensionSecurity.vue +++ b/assets/admin/src/pages/extensions/ExtensionSecurity.vue @@ -216,10 +216,16 @@ async function handleSaveRisk() { async function handleTestIp() { ipTest.value.loading = true + ipTest.value.result = '' try { - const res = await api.testIpGeo(ipTest.value.ip) - ipTest.value.result = JSON.stringify(res?.data || {}, null, 2) - message.success('IP 接口测试完成') + const res = await api.testIpGeo(String(ipTest.value.ip || '').trim()) + const data = res?.data || {} + ipTest.value.result = JSON.stringify(data, null, 2) + if (data.ok) { + message.success(data.display ? `IP 测试成功:${data.display}` : 'IP 接口测试完成') + } else { + message.warning(data.message || '未查询到归属地信息') + } } catch (err) { message.error(err?.message || 'IP 测试失败') } finally { diff --git a/inc/classes/admin/class-aksrt-admin-extension-controller.php b/inc/classes/admin/class-aksrt-admin-extension-controller.php index f48e2c6a..206450e6 100644 --- a/inc/classes/admin/class-aksrt-admin-extension-controller.php +++ b/inc/classes/admin/class-aksrt-admin-extension-controller.php @@ -284,6 +284,9 @@ class AKSRT_Admin_Extension_Controller extends AKSRT_Admin_Controller_Base { /** * POST /extensions/ip-test — test current IP provider with a given IP. + * + * Admin tests force a live lookup (skip enable-gate + cache) so operators can + * verify credentials before flipping the runtime switch. */ public function test_ip_geo(WP_REST_Request $request): WP_REST_Response { $params = $this->get_json_params($request); @@ -297,12 +300,46 @@ class AKSRT_Admin_Extension_Controller extends AKSRT_Admin_Controller_Base { return $this->error(__('IP 归属地服务不可用', 'aksrt'), 500); } - $result = AKSRT_IP_Geo::get_instance()->lookup($ip); + $geo = AKSRT_IP_Geo::get_instance(); + $status = $geo->get_status(); + $result = $geo->lookup($ip, true); + + $reason = (string) ($result['reason'] ?? ''); + $message = ''; + $ok = !empty($result['country']) || !empty($result['province']) || !empty($result['city']); + + if (!$ok) { + switch ($reason) { + case 'private_ip': + $message = __('该地址为私有/保留 IP,无法查询归属地。请换公网 IP 测试。', 'aksrt'); + break; + case 'provider_empty': + if (!empty($status['missing_fields'])) { + $message = sprintf( + /* translators: %s: missing config field keys */ + __('当前服务商凭据不完整(缺少:%s),请先在「扩展 → IP归属地」补全配置。', 'aksrt'), + implode(', ', (array) $status['missing_fields']) + ); + } else { + $message = __('服务商未返回有效归属地,请检查凭据、网络出口或换一个 IP 重试。', 'aksrt'); + } + break; + case 'disabled': + $message = __('IP 归属地功能未启用。', 'aksrt'); + break; + default: + $message = __('未查询到归属地信息。', 'aksrt'); + } + } return $this->success([ 'data' => [ - 'ip' => $ip, - 'result' => $result, + 'ip' => $ip, + 'ok' => $ok, + 'message' => $message, + 'status' => $status, + 'result' => $result, + 'display' => $ok ? $geo->format($result) : '', ], ]); } diff --git a/inc/classes/class-aksrt-ip-geo.php b/inc/classes/class-aksrt-ip-geo.php index 282dd90e..6360e8ad 100644 --- a/inc/classes/class-aksrt-ip-geo.php +++ b/inc/classes/class-aksrt-ip-geo.php @@ -21,33 +21,43 @@ class AKSRT_IP_Geo { /** * 查询 IP 归属地 * - * @param string $ip IPv4 or IPv6 - * @return array{country: string, province: string, city: string, raw: array} + * @param string $ip IPv4 or IPv6 + * @param bool $force 管理端测试用:跳过「启用」开关与缓存,仍拒绝私有 IP + * @return array{country: string, province: string, city: string, raw: array, reason?: string} */ - public function lookup(string $ip): array { + public function lookup(string $ip, bool $force = false): array { $config = $this->get_config(); - if (empty($config['ip_geo_enabled'])) { - return $this->empty_result(); + if (!$force && empty($config['ip_geo_enabled'])) { + return $this->empty_result('disabled'); } // 本地/私有 IP 跳过查询 if ($this->is_private_ip($ip)) { - return $this->empty_result(); + return $this->empty_result('private_ip'); } $cache_key = 'aksrt_ip_geo_' . md5($ip); $ttl = max(3600, (int) ($config['ip_geo_cache_ttl'] ?? 86400)); - $cached = get_transient($cache_key); - if ($cached !== false && is_array($cached)) { - return $cached; + if (!$force) { + $cached = get_transient($cache_key); + if ($cached !== false && is_array($cached)) { + return $cached; + } } $provider = sanitize_key((string) ($config['ip_addr_sdk'] ?? ($config['ip_geo_provider'] ?? 'null'))); $result = $this->query_provider($provider, $ip, $config); - if (!empty($result['province']) || !empty($result['city'])) { - set_transient($cache_key, $result, $ttl); + if (!empty($result['province']) || !empty($result['city']) || !empty($result['country'])) { + if (!$force) { + set_transient($cache_key, $result, $ttl); + } + return $result; + } + + if (empty($result['reason'])) { + $result['reason'] = 'provider_empty'; } return $result; @@ -211,7 +221,11 @@ class AKSRT_IP_Geo { return !filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE); } - private function empty_result(): array { - return ['country' => '', 'province' => '', 'city' => '', 'raw' => []]; + private function empty_result(string $reason = ''): array { + $out = ['country' => '', 'province' => '', 'city' => '', 'raw' => []]; + if ($reason !== '') { + $out['reason'] = $reason; + } + return $out; } }