fix(extensions): IP 归属地管理端测试可绕过启用开关

后台测试此前受 ip_geo_enabled 短路,未启用时结果恒为空;强制 live lookup 并返回可读失败原因。
This commit is contained in:
2026-07-12 14:35:19 +08:00
parent 5c84d259e7
commit 3675b7dcef
4 changed files with 78 additions and 21 deletions
+2 -2
View File
@@ -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') },
@@ -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 {
@@ -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) : '',
],
]);
}
+27 -13
View File
@@ -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;
}
}