From 1a52201ec739aa70112c85fcf87a01c20e7209a6 Mon Sep 17 00:00:00 2001 From: root Date: Mon, 15 Jun 2026 16:53:05 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E5=88=A4=E6=96=AD=E5=85=A5?= =?UTF-8?q?=E5=8F=A3=E6=96=87=E4=BB=B6ip=5Fcheck.php=E4=BB=A5=E5=8F=8A?= =?UTF-8?q?=E6=96=B0=E5=A2=9E=E5=A4=8D=E5=88=B6=E9=85=8D=E7=BD=AE=E9=80=89?= =?UTF-8?q?=E9=A1=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- dashboard.php | 46 +- datatable/datalist.php | 7 +- datatable/sdatalist.php | 7 +- f_check.php | 47 +- jump.txt | 2 + lib/Cloak/CountryAllowlist.php | 7 +- lib/Cloak/CountryCodeNormalizer.php | 60 ++ lib/Cloak/GeoIpCountryCache.php | 26 +- lib/Cloak/GeoIpCountryResolver.php | 13 +- lib/Cloak/Pipeline/RouteResolver.php | 3 +- .../stages/run_main_api_fingerprint.inc.php | 3 + lib/Cloak/RiskSecondaryGate.php | 15 + lib/Cloak/VisitorApiAudit.php | 76 +++ lib/Cloak/VisitorInfo.php | 9 +- lib/Cloak/VisitorLogSchema.php | 4 + lib/Cloak/VisitorLogWorker.php | 12 +- lib/Cloak/VisitorRepository.php | 11 +- lib/Cloak/iso3166_maps.php | 526 ++++++++++++++++++ lib/InstallSchema.php | 4 + lib/bootstrap.php | 3 + lib_FLTSX.zip | Bin 92333 -> 0 bytes table.php | 116 +++- tools/verify_geoip.php | 7 + 23 files changed, 969 insertions(+), 35 deletions(-) create mode 100644 lib/Cloak/CountryCodeNormalizer.php create mode 100644 lib/Cloak/RiskSecondaryGate.php create mode 100644 lib/Cloak/VisitorApiAudit.php create mode 100644 lib/Cloak/iso3166_maps.php delete mode 100755 lib_FLTSX.zip diff --git a/dashboard.php b/dashboard.php index e240e13..6a8e8d0 100755 --- a/dashboard.php +++ b/dashboard.php @@ -35,14 +35,24 @@ if (!empty($_REQUEST["action"]) && $_REQUEST["action"] == "delUrlArgs") { // 确定当前配置上下文(供表单回显用) $isNewConfigDraft = false; +$configCopySource = ''; +$copyFrom = dash_sanitize_config_name($_REQUEST['copy_from'] ?? ''); if (!empty($_REQUEST["name"])) { $check_name = trim($_REQUEST["name"]); $config_name = str_replace(".php", "", $check_name); $config_file = "check_config/" . $config_name . "_config.php"; if (!file_exists($config_file)) { - // 新建或未保存的配置:仅回显 index 模板,不在此写盘 $isNewConfigDraft = true; - $config_file = "check_config/index_config.php"; + $sourceFile = ($copyFrom !== '') ? "check_config/{$copyFrom}_config.php" : ''; + if ($copyFrom !== '' && is_file($sourceFile)) { + $config_file = $sourceFile; + $configCopySource = $copyFrom; + if ($check_name === 'new_config' || $check_name === '') { + $check_name = dash_suggest_copy_config_name($copyFrom); + } + } else { + $config_file = "check_config/index_config.php"; + } } } else { $check_name = "index"; @@ -435,6 +445,31 @@ function dash_check_redis() { } catch (Throwable $e) { return false; } } +function dash_sanitize_config_name($name) +{ + $name = trim(str_replace('.php', '', (string) $name)); + if ($name === '' || !preg_match('/^[a-zA-Z0-9_-]+$/', $name)) { + return ''; + } + return $name; +} + +function dash_suggest_copy_config_name($source) +{ + $source = dash_sanitize_config_name($source); + if ($source === '') { + return 'new_config'; + } + $base = $source . '_copy'; + $candidate = $base; + $suffix = 2; + while (file_exists(__DIR__ . "/check_config/{$candidate}_config.php")) { + $candidate = $base . $suffix; + $suffix++; + } + return $candidate; +} + function dash_cfg_get($raw, $name) { if (preg_match("/define\('" . preg_quote($name, '/') . "',\s*'([^']*)'\)/", $raw, $m)) { @@ -662,7 +697,8 @@ $_d = function($name, $default) { return defined($name) ? constant($name) : $def
- 编辑 + 编辑 + 复制 查看 @@ -776,7 +812,7 @@ $_d = function($name, $default) { return defined($name) ? constant($name) : $def
-
未保存
+
未保存 复制
设置当前浏览器为真实访客 @@ -802,7 +838,7 @@ $_d = function($name, $default) { return defined($name) ? constant($name) : $def 配置名称 - 示例:f123、d258 + diff --git a/datatable/datalist.php b/datatable/datalist.php index 2ec376e..eb993da 100755 --- a/datatable/datalist.php +++ b/datatable/datalist.php @@ -4,6 +4,7 @@ require_once(dirname(__DIR__) . "/cong.php"); require_once(dirname(__DIR__) . "/lib/DbHelper.php"); require_once(dirname(__DIR__) . "/lib/Cloak/PipelineTimer.php"); require_once(dirname(__DIR__) . "/lib/Cloak/VisitorLogSchema.php"); +require_once(dirname(__DIR__) . "/lib/Cloak/VisitorApiAudit.php"); session_start(); $reasons = array( @@ -117,7 +118,7 @@ if ($conn->connect_error) { $where .= " AND " . join(" AND ", $map); } // SQL语句 - $sql = "SELECT `id`, `campagin_id`, `visit_md5_code`, `domain`, `visit_date`, `IP`, `country`, `result`, `reason`, `fp_url`, `referer`, `vtimes`, `client`, `browser`, `page`, `language`, `user_agent`, `http_referer`, `accept_language_raw`, `judge_timing`, `fp_hdata`, `device`, `add_time` FROM `visitor_logs` WHERE {$where} ORDER BY `id` DESC LIMIT {$startPosition}, {$recordsPerPage}"; + $sql = "SELECT `id`, `campagin_id`, `visit_md5_code`, `domain`, `visit_date`, `IP`, `country`, `result`, `reason`, `fp_url`, `referer`, `vtimes`, `client`, `browser`, `page`, `language`, `user_agent`, `http_referer`, `accept_language_raw`, `judge_timing`, `fp_hdata`, `api_by_request`, `api_by_response`, `api_risk_request`, `api_risk_response`, `device`, `add_time` FROM `visitor_logs` WHERE {$where} ORDER BY `id` DESC LIMIT {$startPosition}, {$recordsPerPage}"; // 执行查询并输出结果 $result = mysqli_query($conn, $sql); @@ -167,6 +168,10 @@ if ($conn->connect_error) { $row['fp_hdata_explain_html'] = ''; $row['fp_hdata_explain'] = null; } + $row['api_by_request_text'] = VisitorApiAudit::displayText($row['api_by_request'] ?? ''); + $row['api_by_response_text'] = VisitorApiAudit::displayText($row['api_by_response'] ?? ''); + $row['api_risk_request_text'] = VisitorApiAudit::displayText($row['api_risk_request'] ?? ''); + $row['api_risk_response_text']= VisitorApiAudit::displayText($row['api_risk_response'] ?? ''); $jsonData[] = $row; } diff --git a/datatable/sdatalist.php b/datatable/sdatalist.php index b13167b..249f2d4 100755 --- a/datatable/sdatalist.php +++ b/datatable/sdatalist.php @@ -4,6 +4,7 @@ require_once(dirname(__DIR__) . "/cong.php"); require_once(dirname(__DIR__) . "/lib/DbHelper.php"); require_once(dirname(__DIR__) . "/lib/Cloak/PipelineTimer.php"); require_once(dirname(__DIR__) . "/lib/Cloak/VisitorLogSchema.php"); +require_once(dirname(__DIR__) . "/lib/Cloak/VisitorApiAudit.php"); $reasons = array( "blank_referrer" => "过滤无来源的访问", @@ -111,7 +112,7 @@ if ($conn->connect_error) { $where .= " AND " . join(" AND ", $map); } // SQL语句 - $sql = "SELECT `id`, `campagin_id`, `visit_md5_code`, `domain`, `visit_date`, `IP`, `country`, `result`, `reason`, `fp_url`, `referer`, `vtimes`, `client`, `browser`, `page`, `language`, `user_agent`, `http_referer`, `accept_language_raw`, `judge_timing`, `fp_hdata`, `device`, `add_time` FROM `visitor_logs` WHERE {$where} ORDER BY `id` DESC LIMIT {$startPosition}, {$recordsPerPage}"; + $sql = "SELECT `id`, `campagin_id`, `visit_md5_code`, `domain`, `visit_date`, `IP`, `country`, `result`, `reason`, `fp_url`, `referer`, `vtimes`, `client`, `browser`, `page`, `language`, `user_agent`, `http_referer`, `accept_language_raw`, `judge_timing`, `fp_hdata`, `api_by_request`, `api_by_response`, `api_risk_request`, `api_risk_response`, `device`, `add_time` FROM `visitor_logs` WHERE {$where} ORDER BY `id` DESC LIMIT {$startPosition}, {$recordsPerPage}"; // 执行查询并输出结果 $result = mysqli_query($conn, $sql); @@ -157,6 +158,10 @@ if ($conn->connect_error) { $row['fp_hdata_explain_html'] = ''; $row['fp_hdata_explain'] = null; } + $row['api_by_request_text'] = VisitorApiAudit::displayText($row['api_by_request'] ?? ''); + $row['api_by_response_text'] = VisitorApiAudit::displayText($row['api_by_response'] ?? ''); + $row['api_risk_request_text'] = VisitorApiAudit::displayText($row['api_risk_request'] ?? ''); + $row['api_risk_response_text']= VisitorApiAudit::displayText($row['api_risk_response'] ?? ''); $jsonData[] = $row; } diff --git a/f_check.php b/f_check.php index 4d1f71f..07eecd0 100755 --- a/f_check.php +++ b/f_check.php @@ -37,6 +37,8 @@ require_once __DIR__ . '/lib/DbHelper.php'; require_once __DIR__ . '/lib/bootstrap.php'; require_once __DIR__ . '/config/ConfigLoader.php'; require_once __DIR__ . '/lib/Cloak/FpUrlHelper.php'; +require_once __DIR__ . '/lib/Cloak/VisitorApiAudit.php'; +require_once __DIR__ . '/lib/Cloak/RiskSecondaryGate.php'; $fp_host = parse_url($fingerprint_info['domain'], PHP_URL_HOST); if (empty($fp_host)) { @@ -44,6 +46,41 @@ if (empty($fp_host)) { } $config_name = ConfigLoader::loadByHost($fp_host); +$log_id = (int) ($fingerprint_info['log_id'] ?? 0); + +if (!RiskSecondaryGate::isEnabled()) { + $_SESSION['visit_to_3'] = 3; + $_SESSION['check_result'] = 'true'; + + $resolved = FpUrlHelper::resolve($config_name, true); + $fp_url = $resolved['url']; + $response = [ + 'reason' => '', + 'result' => true, + 'link' => $fp_url !== '' ? $fp_url : FpUrlHelper::fallbackUrl(), + ]; + + if ($log_id > 0) { + $conn = new mysqli('localhost', DB_USERNAME, DB_PASSWORD, DB_NAME); + if (!$conn->connect_error) { + require_once __DIR__ . '/lib/Cloak/VisitorLogSchema.php'; + VisitorLogSchema::ensureColumns($conn); + $resultEsc = cloak_db_escape($conn, 'true'); + $reasonEsc = cloak_db_escape($conn, '二次风控已关闭'); + $fpUrlEsc = cloak_db_escape($conn, strip_tags(cloak_db_string($response['link']))); + $sql = "UPDATE `visitor_logs` SET `result`='{$resultEsc}',`reason`='{$reasonEsc}',`fp_url`='{$fpUrlEsc}' WHERE `id`='" . $log_id . "'"; + if ($conn->query($sql) !== true) { + $handle = fopen(dirname(__FILE__) . '/err.txt', 'a+'); + fwrite($handle, date('Y-m-d H:i:s') . ' | f_check risk disabled update: ' . $conn->error . "\n"); + fclose($handle); + } + $conn->close(); + } + } + + exit(json_encode($response)); +} + $jsonData = [ 'id' => COSTM_IP_SCORE, 'hdata' => $hdata, @@ -54,7 +91,7 @@ $jsonData = [ 'risk_number' => CLOAK_RISK_NUMBER, ]; -$ch = curl_init('https://www.tiktokba.com/cloak/byApiRisk'); +$ch = curl_init('www.tiktokba.com/cloak/byApiRisk'); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4); @@ -114,10 +151,8 @@ if($return['result']) { } } -$log_id = (int) ($fingerprint_info['log_id'] ?? 0); $update_log = []; - -$update_log['result'] = $response['result'] ? "true" : "false"; +$update_log['result'] = $response['result'] ? 'true' : 'false'; $update_log['reason'] = $response['reason'] ?? ''; $update_log['fp_url'] = trim((string) ($response['link'] ?? '')); if ($update_log['fp_url'] === '') { @@ -148,9 +183,11 @@ if ($conn->connect_error) { $fpHdataJson = ''; } $fpHdataEsc = cloak_db_escape($conn, $fpHdataJson); + $apiRiskReqEsc = cloak_db_escape($conn, VisitorApiAudit::encode($jsonData)); + $apiRiskRespEsc = cloak_db_escape($conn, VisitorApiAudit::encode($return)); require_once __DIR__ . '/lib/Cloak/VisitorLogSchema.php'; VisitorLogSchema::ensureColumns($conn); - $sql = "UPDATE `visitor_logs` SET `result`='{$resultEsc}',`reason`='{$reasonEsc}',`fp_url`='{$fpUrlEsc}',`fp_hdata`='{$fpHdataEsc}' WHERE `id`='" . (int) $log_id . "'"; + $sql = "UPDATE `visitor_logs` SET `result`='{$resultEsc}',`reason`='{$reasonEsc}',`fp_url`='{$fpUrlEsc}',`fp_hdata`='{$fpHdataEsc}',`api_risk_request`='{$apiRiskReqEsc}',`api_risk_response`='{$apiRiskRespEsc}' WHERE `id`='" . (int) $log_id . "'"; if ($conn->query($sql) != TRUE) { $handle = fopen(dirname(__FILE__) . "/err.txt", "a+"); diff --git a/jump.txt b/jump.txt index 79abc70..8b31ca2 100755 --- a/jump.txt +++ b/jump.txt @@ -99,3 +99,5 @@ 2026-06-14 15:23:23 | 写入数据库 | | regression_test | async=1 2026-06-14 15:47:16 | 来源判断 | 无法识别访客国家|false | index | 127.0.0.1 | https://www.baidu.com/ 2026-06-14 15:47:16 | 写入数据库 | false | index | async=1 +2026-06-15 16:45:08 | 来源判断 | 无法识别访客国家|false | index | 127.0.0.1 | https://www.baidu.com/ +2026-06-15 16:45:08 | 写入数据库 | false | index | async=1 diff --git a/lib/Cloak/CountryAllowlist.php b/lib/Cloak/CountryAllowlist.php index fe0f0eb..47f2609 100644 --- a/lib/Cloak/CountryAllowlist.php +++ b/lib/Cloak/CountryAllowlist.php @@ -2,6 +2,8 @@ /** * SHOW_SITE_COUNTRY 允许列表解析与比对 */ +require_once __DIR__ . '/CountryCodeNormalizer.php'; + class CountryAllowlist { /** @@ -34,9 +36,10 @@ class CountryAllowlist if ($allowlist === []) { return true; } - if ($countryCode === null || $countryCode === '') { + $normalized = CountryCodeNormalizer::toAlpha2($countryCode); + if ($normalized === null || $normalized === '') { return false; } - return in_array(strtoupper($countryCode), $allowlist, true); + return in_array($normalized, $allowlist, true); } } diff --git a/lib/Cloak/CountryCodeNormalizer.php b/lib/Cloak/CountryCodeNormalizer.php new file mode 100644 index 0000000..8f37331 --- /dev/null +++ b/lib/Cloak/CountryCodeNormalizer.php @@ -0,0 +1,60 @@ +,alpha3:array}|null */ + private static $maps = null; + + /** + * @param mixed $value ISO2、ISO3 或英文国名 + * @return string|null 两位国家码;无法识别时 null + */ + public static function toAlpha2($value) + { + $value = trim((string) $value); + if ($value === '') { + return null; + } + + $upper = strtoupper($value); + if (preg_match('/^[A-Z]{2}$/', $upper)) { + return $upper; + } + + $maps = self::maps(); + if (preg_match('/^[A-Z]{3}$/', $upper) && isset($maps['alpha3'][$upper])) { + return $maps['alpha3'][$upper]; + } + + $nameKey = self::nameKey($value); + if (isset($maps['names'][$nameKey])) { + return $maps['names'][$nameKey]; + } + + return null; + } + + /** + * @return array{names:array,alpha3:array} + */ + private static function maps() + { + if (self::$maps === null) { + $file = __DIR__ . '/iso3166_maps.php'; + $data = is_file($file) ? require $file : ['names' => [], 'alpha3' => []]; + self::$maps = [ + 'names' => isset($data['names']) && is_array($data['names']) ? $data['names'] : [], + 'alpha3' => isset($data['alpha3']) && is_array($data['alpha3']) ? $data['alpha3'] : [], + ]; + } + return self::$maps; + } + + private static function nameKey($name) + { + $name = preg_replace('/\s+/u', ' ', trim((string) $name)); + return strtoupper($name); + } +} diff --git a/lib/Cloak/GeoIpCountryCache.php b/lib/Cloak/GeoIpCountryCache.php index 6428832..e849d99 100644 --- a/lib/Cloak/GeoIpCountryCache.php +++ b/lib/Cloak/GeoIpCountryCache.php @@ -2,6 +2,8 @@ /** * IP → 国家码跨请求缓存(Redis 优先,文件降级,默认 TTL 30 天) */ +require_once __DIR__ . '/CountryCodeNormalizer.php'; + class GeoIpCountryCache { const REDIS_PREFIX = 'cloak:geoip:cc:'; @@ -28,7 +30,7 @@ class GeoIpCountryCache if ($value === false || $value === null) { return false; } - return $value === self::NONE_SENTINEL ? null : (string) $value; + return self::normalizeCachedValue($value === self::NONE_SENTINEL ? null : (string) $value); } catch (Throwable $e) { self::logError('Redis get failed: ' . $e->getMessage()); } @@ -48,7 +50,12 @@ class GeoIpCountryCache return; } - $value = $countryCode !== null && $countryCode !== '' ? strtoupper($countryCode) : self::NONE_SENTINEL; + if ($countryCode !== null && $countryCode !== '') { + $normalized = CountryCodeNormalizer::toAlpha2($countryCode); + $value = $normalized !== null ? $normalized : strtoupper($countryCode); + } else { + $value = self::NONE_SENTINEL; + } $ttl = self::cacheTtl(); $redis = self::redisClient(); @@ -137,7 +144,20 @@ class GeoIpCountryCache @unlink($path); return false; } - return $data['value'] === self::NONE_SENTINEL ? null : (string) $data['value']; + return self::normalizeCachedValue($data['value'] === self::NONE_SENTINEL ? null : (string) $data['value']); + } + + /** + * @param string|null $value + * @return string|null + */ + private static function normalizeCachedValue($value) + { + if ($value === null || $value === '') { + return null; + } + $normalized = CountryCodeNormalizer::toAlpha2($value); + return $normalized !== null ? $normalized : strtoupper((string) $value); } /** diff --git a/lib/Cloak/GeoIpCountryResolver.php b/lib/Cloak/GeoIpCountryResolver.php index 660b860..8c0ba3e 100644 --- a/lib/Cloak/GeoIpCountryResolver.php +++ b/lib/Cloak/GeoIpCountryResolver.php @@ -1,4 +1,6 @@ country($ip); - $code = $record->country->isoCode ?? null; - if ($code === null || $code === '') { - return null; + $isoCode = $record->country->isoCode ?? null; + $name = $record->country->name ?? null; + + $code = CountryCodeNormalizer::toAlpha2($isoCode); + if ($code === null && $name !== null && $name !== '') { + $code = CountryCodeNormalizer::toAlpha2($name); } - return strtoupper((string) $code); + return $code; } catch (GeoIp2\Exception\AddressNotFoundException $e) { return null; } catch (Throwable $e) { diff --git a/lib/Cloak/Pipeline/RouteResolver.php b/lib/Cloak/Pipeline/RouteResolver.php index 890113d..e1ed481 100755 --- a/lib/Cloak/Pipeline/RouteResolver.php +++ b/lib/Cloak/Pipeline/RouteResolver.php @@ -2,6 +2,7 @@ require_once __DIR__ . '/../Page/FpPageRenderer.php'; require_once __DIR__ . '/../Page/RiskPageRenderer.php'; require_once __DIR__ . '/../FpUrlHelper.php'; +require_once __DIR__ . '/../RiskSecondaryGate.php'; /** * 判定完成后的路由输出(真实页 / 安全页 / 二次风控) @@ -78,7 +79,7 @@ class RouteResolver $_SESSION['visit_to_3'] = '1'; } if (($_SESSION['visit_to_3'] ?? '1') != '3' - && (CLOAK_RISK_NUMBER > 0 && CLOAK_RISK_NUMBER <= 90)) { + && RiskSecondaryGate::isEnabled()) { // 二次风控:先写 wait 状态,f_check 完成后再更新 result / fp_url(避免 true+空跳转) $logs['result'] = 'wait'; $logs['reason'] = '二次风控检测中'; diff --git a/lib/Cloak/Pipeline/stages/run_main_api_fingerprint.inc.php b/lib/Cloak/Pipeline/stages/run_main_api_fingerprint.inc.php index de0d1fe..d8e59f0 100755 --- a/lib/Cloak/Pipeline/stages/run_main_api_fingerprint.inc.php +++ b/lib/Cloak/Pipeline/stages/run_main_api_fingerprint.inc.php @@ -17,6 +17,9 @@ $_SESSION["gcu_Client"] = ''; $_SESSION["gcu_ip"] = ''; $_SESSION["gcu_Browser"] = ''; + if (class_exists('VisitorApiAudit', false)) { + VisitorApiAudit::clearByApi(); + } } if($_SESSION['visit_to_1'] == '1' && $_SESSION['visit_to_2'] != '2') // $_SESSION['visit_to_2'] 为2时表示已经判断过所有规则。 diff --git a/lib/Cloak/RiskSecondaryGate.php b/lib/Cloak/RiskSecondaryGate.php new file mode 100644 index 0000000..aab93fa --- /dev/null +++ b/lib/Cloak/RiskSecondaryGate.php @@ -0,0 +1,15 @@ + 0 && $riskNumber <= 90; + } +} diff --git a/lib/Cloak/VisitorApiAudit.php b/lib/Cloak/VisitorApiAudit.php new file mode 100644 index 0000000..669d736 --- /dev/null +++ b/lib/Cloak/VisitorApiAudit.php @@ -0,0 +1,76 @@ + self::SESSION_BY_REQUEST, + 'api_by_response' => self::SESSION_BY_RESPONSE, + ]; + foreach ($map as $col => $sessionKey) { + if (empty($logs[$col]) && !empty($_SESSION[$sessionKey])) { + $logs[$col] = (string) $_SESSION[$sessionKey]; + } + } + return $logs; + } + + /** + * @param mixed $data + */ + public static function encode($data) + { + if (is_string($data)) { + return $data; + } + $json = json_encode($data, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES); + return $json !== false ? $json : ''; + } + + /** + * 日志表格展示:未调用时返回「-」 + * + * @param mixed $raw + */ + public static function displayText($raw) + { + $raw = trim((string) $raw); + return $raw === '' ? '-' : $raw; + } +} diff --git a/lib/Cloak/VisitorInfo.php b/lib/Cloak/VisitorInfo.php index b80fbd2..51377e8 100755 --- a/lib/Cloak/VisitorInfo.php +++ b/lib/Cloak/VisitorInfo.php @@ -1,5 +1,6 @@ check_country; //设置该参数后,将替换"广告策略》访问者地理位置>过滤"的设置,填写国家代码,多个用逗号分隔,如:US,GB,CA,AU,IE,NZ $jsonData['referer'] = get_SERVER_value('HTTP_REFERER'); $jsonData['headers'] = json_encode($headers); + VisitorApiAudit::recordByApiRequest($jsonData); $ch = curl_init('www.tiktokba.com/cloak/byApi'); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); @@ -114,14 +116,19 @@ class visitorInfo if ($return == false) { $curl_error = curl_error($ch); curl_close($ch); - return ['result' => false, 'reason' => 'API请求失败:' . $curl_error, 'country' => '']; + $errorPayload = ['result' => false, 'reason' => 'API请求失败:' . $curl_error, 'country' => '']; + VisitorApiAudit::recordByApiResponse($errorPayload); + return $errorPayload; } curl_close($ch); $decoded = json_decode($return, true); if (!is_array($decoded)) { + $invalidPayload = ['result' => false, 'reason' => 'API响应失败,请检查API密钥以及广告策略 ID', 'country' => '', '_raw' => $return]; + VisitorApiAudit::recordByApiResponse($invalidPayload); return ['result' => false, 'reason' => 'API响应失败,请检查API密钥以及广告策略 ID', 'country' => '']; } + VisitorApiAudit::recordByApiResponse($decoded); return $decoded; } diff --git a/lib/Cloak/VisitorLogSchema.php b/lib/Cloak/VisitorLogSchema.php index 0f33963..2af4943 100755 --- a/lib/Cloak/VisitorLogSchema.php +++ b/lib/Cloak/VisitorLogSchema.php @@ -24,6 +24,10 @@ class VisitorLogSchema 'accept_language_raw' => "ALTER TABLE `visitor_logs` ADD COLUMN `accept_language_raw` TEXT NULL COMMENT 'Accept-Language 完整值' AFTER `http_referer`", 'judge_timing' => "ALTER TABLE `visitor_logs` ADD COLUMN `judge_timing` TEXT NULL COMMENT '判定用时 JSON' AFTER `accept_language_raw`", 'fp_hdata' => "ALTER TABLE `visitor_logs` ADD COLUMN `fp_hdata` TEXT NULL COMMENT '指纹 hdata 解码 JSON' AFTER `judge_timing`", + 'api_by_request' => "ALTER TABLE `visitor_logs` ADD COLUMN `api_by_request` TEXT NULL COMMENT 'byApi 请求参数 JSON' AFTER `fp_hdata`", + 'api_by_response' => "ALTER TABLE `visitor_logs` ADD COLUMN `api_by_response` TEXT NULL COMMENT 'byApi 响应 JSON' AFTER `api_by_request`", + 'api_risk_request' => "ALTER TABLE `visitor_logs` ADD COLUMN `api_risk_request` TEXT NULL COMMENT 'byApiRisk 请求参数 JSON' AFTER `api_by_response`", + 'api_risk_response' => "ALTER TABLE `visitor_logs` ADD COLUMN `api_risk_response` TEXT NULL COMMENT 'byApiRisk 响应 JSON' AFTER `api_risk_request`", ]; foreach ($columns as $name => $ddl) { if (!self::columnExists($conn, 'visitor_logs', $name)) { diff --git a/lib/Cloak/VisitorLogWorker.php b/lib/Cloak/VisitorLogWorker.php index a9724c7..cb5ef7f 100644 --- a/lib/Cloak/VisitorLogWorker.php +++ b/lib/Cloak/VisitorLogWorker.php @@ -70,7 +70,7 @@ class VisitorLogWorker return array_key_exists($key, $data) ? $data[$key] : cloak_db_escape($conn, ''); }; - $sql = "INSERT INTO `visitor_logs`(`campagin_id`, `visit_md5_code`, `domain`, `visit_date`, `IP`, `country`, `result`, `reason`, `referer`, `client`, `browser`, `page`, `language`, `user_agent`, `http_referer`, `accept_language_raw`, `judge_timing`, `fp_url`, `device`) VALUES ('" + $sql = "INSERT INTO `visitor_logs`(`campagin_id`, `visit_md5_code`, `domain`, `visit_date`, `IP`, `country`, `result`, `reason`, `referer`, `client`, `browser`, `page`, `language`, `user_agent`, `http_referer`, `accept_language_raw`, `judge_timing`, `fp_url`, `device`, `api_by_request`, `api_by_response`, `api_risk_request`, `api_risk_response`) VALUES ('" . $d('campagin_id') . "','" . $d('visit_md5_code') . "','" . $d('site_name') . "','" @@ -89,7 +89,11 @@ class VisitorLogWorker . $d('accept_language_raw') . "','" . $d('judge_timing') . "','" . $d('fp_url') . "','" - . $d('device') . "')"; + . $d('device') . "','" + . $d('api_by_request') . "','" + . $d('api_by_response') . "','" + . $d('api_risk_request') . "','" + . $d('api_risk_response') . "')"; if ($conn->query($sql) !== true) { VisitorLogQueue::logError('insert_full: ' . $conn->error . ' | ' . $sql); @@ -169,6 +173,10 @@ class VisitorLogWorker 'http_referer' => 'http_referer', 'accept_language_raw' => 'accept_language_raw', 'judge_timing' => 'judge_timing', + 'api_by_request' => 'api_by_request', + 'api_by_response' => 'api_by_response', + 'api_risk_request' => 'api_risk_request', + 'api_risk_response' => 'api_risk_response', ]; foreach ($map as $col => $logKey) { if (array_key_exists($logKey, $data)) { diff --git a/lib/Cloak/VisitorRepository.php b/lib/Cloak/VisitorRepository.php index 99e3a9f..0636855 100755 --- a/lib/Cloak/VisitorRepository.php +++ b/lib/Cloak/VisitorRepository.php @@ -4,6 +4,7 @@ */ require_once dirname(__DIR__) . '/DbHelper.php'; require_once dirname(__DIR__) . '/CloakHttpHelpers.php'; +require_once __DIR__ . '/VisitorApiAudit.php'; if (!function_exists('cloak_session_mark_real_visitor')) { /** @@ -123,7 +124,7 @@ if (!function_exists('cloak_visitor_log_enrich')) { if (empty($logs['judge_timing']) && !empty($GLOBALS['__cloak_judge_timing'])) { $logs['judge_timing'] = $GLOBALS['__cloak_judge_timing']; } - return $logs; + return VisitorApiAudit::mergeIntoLogs($logs); } } @@ -209,7 +210,7 @@ if (!function_exists('cloak_write_log_db')) { $d = static function ($key) use ($data, $conn) { return array_key_exists($key, $data) ? $data[$key] : cloak_db_escape($conn, ''); }; - $sql = "INSERT INTO `visitor_logs`(`campagin_id`, `visit_md5_code`, `domain`, `visit_date`, `IP`, `country`, `result`, `reason`, `referer`, `client`, `browser`, `page`, `language`, `user_agent`, `http_referer`, `accept_language_raw`, `judge_timing`, `fp_url`, `device`) VALUES ('" + $sql = "INSERT INTO `visitor_logs`(`campagin_id`, `visit_md5_code`, `domain`, `visit_date`, `IP`, `country`, `result`, `reason`, `referer`, `client`, `browser`, `page`, `language`, `user_agent`, `http_referer`, `accept_language_raw`, `judge_timing`, `fp_url`, `device`, `api_by_request`, `api_by_response`, `api_risk_request`, `api_risk_response`) VALUES ('" . $d('campagin_id') . "','" . $d('visit_md5_code') . "','" . $d('site_name') . "','" @@ -228,7 +229,11 @@ if (!function_exists('cloak_write_log_db')) { . $d('accept_language_raw') . "','" . $d('judge_timing') . "','" . $d('fp_url') . "','" - . $d('device') . "')"; + . $d('device') . "','" + . $d('api_by_request') . "','" + . $d('api_by_response') . "','" + . $d('api_risk_request') . "','" + . $d('api_risk_response') . "')"; if ($conn->query($sql) === true) { $last_id = $conn->insert_id; $conn->close(); diff --git a/lib/Cloak/iso3166_maps.php b/lib/Cloak/iso3166_maps.php new file mode 100644 index 0000000..692e587 --- /dev/null +++ b/lib/Cloak/iso3166_maps.php @@ -0,0 +1,526 @@ + [ + 'AFGHANISTAN' => 'AF', + 'ÅLAND ISLANDS' => 'AX', + 'ALBANIA' => 'AL', + 'ALGERIA' => 'DZ', + 'AMERICAN SAMOA' => 'AS', + 'ANDORRA' => 'AD', + 'ANGOLA' => 'AO', + 'ANGUILLA' => 'AI', + 'ANTARCTICA' => 'AQ', + 'ANTIGUA AND BARBUDA' => 'AG', + 'ARGENTINA' => 'AR', + 'ARMENIA' => 'AM', + 'ARUBA' => 'AW', + 'AUSTRALIA' => 'AU', + 'AUSTRIA' => 'AT', + 'AZERBAIJAN' => 'AZ', + 'BAHAMAS' => 'BS', + 'BAHRAIN' => 'BH', + 'BANGLADESH' => 'BD', + 'BARBADOS' => 'BB', + 'BELARUS' => 'BY', + 'BELGIUM' => 'BE', + 'BELIZE' => 'BZ', + 'BENIN' => 'BJ', + 'BERMUDA' => 'BM', + 'BHUTAN' => 'BT', + 'BOLIVIA' => 'BO', + 'BONAIRE, SINT EUSTATIUS AND SABA' => 'BQ', + 'BOSNIA AND HERZEGOVINA' => 'BA', + 'BOTSWANA' => 'BW', + 'BOUVET ISLAND' => 'BV', + 'BRAZIL' => 'BR', + 'BRITISH INDIAN OCEAN TERRITORY' => 'IO', + 'BRUNEI DARUSSALAM' => 'BN', + 'BULGARIA' => 'BG', + 'BURKINA FASO' => 'BF', + 'BURUNDI' => 'BI', + 'CABO VERDE' => 'CV', + 'CAMBODIA' => 'KH', + 'CAMEROON' => 'CM', + 'CANADA' => 'CA', + 'CAYMAN ISLANDS' => 'KY', + 'CENTRAL AFRICAN REPUBLIC' => 'CF', + 'CHAD' => 'TD', + 'CHILE' => 'CL', + 'CHINA' => 'CN', + 'CHRISTMAS ISLAND' => 'CX', + 'COCOS (KEELING) ISLANDS' => 'CC', + 'COLOMBIA' => 'CO', + 'COMOROS' => 'KM', + 'CONGO' => 'CG', + 'CONGO, DEMOCRATIC REPUBLIC OF THE' => 'CD', + 'COOK ISLANDS' => 'CK', + 'COSTA RICA' => 'CR', + 'CÔTE D\'IVOIRE' => 'CI', + 'CROATIA' => 'HR', + 'CUBA' => 'CU', + 'CURAÇAO' => 'CW', + 'CYPRUS' => 'CY', + 'CZECHIA' => 'CZ', + 'DENMARK' => 'DK', + 'DJIBOUTI' => 'DJ', + 'DOMINICA' => 'DM', + 'DOMINICAN REPUBLIC' => 'DO', + 'ECUADOR' => 'EC', + 'EGYPT' => 'EG', + 'EL SALVADOR' => 'SV', + 'EQUATORIAL GUINEA' => 'GQ', + 'ERITREA' => 'ER', + 'ESTONIA' => 'EE', + 'ESWATINI' => 'SZ', + 'ETHIOPIA' => 'ET', + 'FALKLAND ISLANDS' => 'FK', + 'FAROE ISLANDS' => 'FO', + 'FIJI' => 'FJ', + 'FINLAND' => 'FI', + 'FRANCE' => 'FR', + 'FRENCH GUIANA' => 'GF', + 'FRENCH POLYNESIA' => 'PF', + 'FRENCH SOUTHERN TERRITORIES' => 'TF', + 'GABON' => 'GA', + 'GAMBIA' => 'GM', + 'GEORGIA' => 'GE', + 'GERMANY' => 'DE', + 'GHANA' => 'GH', + 'GIBRALTAR' => 'GI', + 'GREECE' => 'GR', + 'GREENLAND' => 'GL', + 'GRENADA' => 'GD', + 'GUADELOUPE' => 'GP', + 'GUAM' => 'GU', + 'GUATEMALA' => 'GT', + 'GUERNSEY' => 'GG', + 'GUINEA' => 'GN', + 'GUINEA-BISSAU' => 'GW', + 'GUYANA' => 'GY', + 'HAITI' => 'HT', + 'HEARD ISLAND AND MCDONALD ISLANDS' => 'HM', + 'HOLY SEE' => 'VA', + 'HONDURAS' => 'HN', + 'HONG KONG' => 'HK', + 'HUNGARY' => 'HU', + 'ICELAND' => 'IS', + 'INDIA' => 'IN', + 'INDONESIA' => 'ID', + 'IRAN' => 'IR', + 'IRAQ' => 'IQ', + 'IRELAND' => 'IE', + 'ISLE OF MAN' => 'IM', + 'ISRAEL' => 'IL', + 'ITALY' => 'IT', + 'JAMAICA' => 'JM', + 'JAPAN' => 'JP', + 'JERSEY' => 'JE', + 'JORDAN' => 'JO', + 'KAZAKHSTAN' => 'KZ', + 'KENYA' => 'KE', + 'KIRIBATI' => 'KI', + 'KOREA, DEMOCRATIC PEOPLE\'S REPUBLIC OF' => 'KP', + 'KOREA, REPUBLIC OF' => 'KR', + 'KUWAIT' => 'KW', + 'KYRGYZSTAN' => 'KG', + 'LAO PEOPLE\'S DEMOCRATIC REPUBLIC' => 'LA', + 'LATVIA' => 'LV', + 'LEBANON' => 'LB', + 'LESOTHO' => 'LS', + 'LIBERIA' => 'LR', + 'LIBYA' => 'LY', + 'LIECHTENSTEIN' => 'LI', + 'LITHUANIA' => 'LT', + 'LUXEMBOURG' => 'LU', + 'MACAO' => 'MO', + 'MADAGASCAR' => 'MG', + 'MALAWI' => 'MW', + 'MALAYSIA' => 'MY', + 'MALDIVES' => 'MV', + 'MALI' => 'ML', + 'MALTA' => 'MT', + 'MARSHALL ISLANDS' => 'MH', + 'MARTINIQUE' => 'MQ', + 'MAURITANIA' => 'MR', + 'MAURITIUS' => 'MU', + 'MAYOTTE' => 'YT', + 'MEXICO' => 'MX', + 'MICRONESIA' => 'FM', + 'MOLDOVA' => 'MD', + 'MONACO' => 'MC', + 'MONGOLIA' => 'MN', + 'MONTENEGRO' => 'ME', + 'MONTSERRAT' => 'MS', + 'MOROCCO' => 'MA', + 'MOZAMBIQUE' => 'MZ', + 'MYANMAR' => 'MM', + 'NAMIBIA' => 'NA', + 'NAURU' => 'NR', + 'NEPAL' => 'NP', + 'NETHERLANDS' => 'NL', + 'NEW CALEDONIA' => 'NC', + 'NEW ZEALAND' => 'NZ', + 'NICARAGUA' => 'NI', + 'NIGER' => 'NE', + 'NIGERIA' => 'NG', + 'NIUE' => 'NU', + 'NORFOLK ISLAND' => 'NF', + 'NORTH MACEDONIA' => 'MK', + 'NORTHERN MARIANA ISLANDS' => 'MP', + 'NORWAY' => 'NO', + 'OMAN' => 'OM', + 'PAKISTAN' => 'PK', + 'PALAU' => 'PW', + 'PALESTINE, STATE OF' => 'PS', + 'PANAMA' => 'PA', + 'PAPUA NEW GUINEA' => 'PG', + 'PARAGUAY' => 'PY', + 'PERU' => 'PE', + 'PHILIPPINES' => 'PH', + 'PITCAIRN' => 'PN', + 'POLAND' => 'PL', + 'PORTUGAL' => 'PT', + 'PUERTO RICO' => 'PR', + 'QATAR' => 'QA', + 'RÉUNION' => 'RE', + 'ROMANIA' => 'RO', + 'RUSSIAN FEDERATION' => 'RU', + 'RWANDA' => 'RW', + 'SAINT BARTHÉLEMY' => 'BL', + 'SAINT HELENA, ASCENSION AND TRISTAN DA CUNHA' => 'SH', + 'SAINT KITTS AND NEVIS' => 'KN', + 'SAINT LUCIA' => 'LC', + 'SAINT MARTIN' => 'MF', + 'SAINT PIERRE AND MIQUELON' => 'PM', + 'SAINT VINCENT AND THE GRENADINES' => 'VC', + 'SAMOA' => 'WS', + 'SAN MARINO' => 'SM', + 'SAO TOME AND PRINCIPE' => 'ST', + 'SAUDI ARABIA' => 'SA', + 'SENEGAL' => 'SN', + 'SERBIA' => 'RS', + 'SEYCHELLES' => 'SC', + 'SIERRA LEONE' => 'SL', + 'SINGAPORE' => 'SG', + 'SINT MAARTEN' => 'SX', + 'SLOVAKIA' => 'SK', + 'SLOVENIA' => 'SI', + 'SOLOMON ISLANDS' => 'SB', + 'SOMALIA' => 'SO', + 'SOUTH AFRICA' => 'ZA', + 'SOUTH GEORGIA AND THE SOUTH SANDWICH ISLANDS' => 'GS', + 'SOUTH SUDAN' => 'SS', + 'SPAIN' => 'ES', + 'SRI LANKA' => 'LK', + 'SUDAN' => 'SD', + 'SURINAME' => 'SR', + 'SVALBARD AND JAN MAYEN' => 'SJ', + 'SWEDEN' => 'SE', + 'SWITZERLAND' => 'CH', + 'SYRIAN ARAB REPUBLIC' => 'SY', + 'TAIWAN' => 'TW', + 'TAJIKISTAN' => 'TJ', + 'TANZANIA' => 'TZ', + 'THAILAND' => 'TH', + 'TIMOR-LESTE' => 'TL', + 'TOGO' => 'TG', + 'TOKELAU' => 'TK', + 'TONGA' => 'TO', + 'TRINIDAD AND TOBAGO' => 'TT', + 'TUNISIA' => 'TN', + 'TÜRKIYE' => 'TR', + 'TURKMENISTAN' => 'TM', + 'TURKS AND CAICOS ISLANDS' => 'TC', + 'TUVALU' => 'TV', + 'UGANDA' => 'UG', + 'UKRAINE' => 'UA', + 'UNITED ARAB EMIRATES' => 'AE', + 'UNITED KINGDOM' => 'GB', + 'UNITED STATES OF AMERICA' => 'US', + 'UNITED STATES MINOR OUTLYING ISLANDS' => 'UM', + 'URUGUAY' => 'UY', + 'UZBEKISTAN' => 'UZ', + 'VANUATU' => 'VU', + 'VENEZUELA' => 'VE', + 'VIET NAM' => 'VN', + 'VIRGIN ISLANDS, BRITISH' => 'VG', + 'VIRGIN ISLANDS, U.S.' => 'VI', + 'WALLIS AND FUTUNA' => 'WF', + 'WESTERN SAHARA' => 'EH', + 'YEMEN' => 'YE', + 'ZAMBIA' => 'ZM', + 'ZIMBABWE' => 'ZW', + 'UNITED STATES' => 'US', + 'USA' => 'US', + 'U.S.A.' => 'US', + 'U.S.' => 'US', + 'UK' => 'GB', + 'GREAT BRITAIN' => 'GB', + 'ENGLAND' => 'GB', + 'RUSSIA' => 'RU', + 'SOUTH KOREA' => 'KR', + 'NORTH KOREA' => 'KP', + 'KOREA' => 'KR', + 'VIETNAM' => 'VN', + 'CZECH REPUBLIC' => 'CZ', + 'SYRIA' => 'SY', + 'LAOS' => 'LA', + 'MACAU' => 'MO', + 'HOLLAND' => 'NL', + 'THE NETHERLANDS' => 'NL', + 'IVORY COAST' => 'CI', + 'TURKEY' => 'TR', + ], + 'alpha3' => [ + 'AFG' => 'AF', + 'ALA' => 'AX', + 'ALB' => 'AL', + 'DZA' => 'DZ', + 'ASM' => 'AS', + 'AND' => 'AD', + 'AGO' => 'AO', + 'AIA' => 'AI', + 'ATA' => 'AQ', + 'ATG' => 'AG', + 'ARG' => 'AR', + 'ARM' => 'AM', + 'ABW' => 'AW', + 'AUS' => 'AU', + 'AUT' => 'AT', + 'AZE' => 'AZ', + 'BHS' => 'BS', + 'BHR' => 'BH', + 'BGD' => 'BD', + 'BRB' => 'BB', + 'BLR' => 'BY', + 'BEL' => 'BE', + 'BLZ' => 'BZ', + 'BEN' => 'BJ', + 'BMU' => 'BM', + 'BTN' => 'BT', + 'BOL' => 'BO', + 'BES' => 'BQ', + 'BIH' => 'BA', + 'BWA' => 'BW', + 'BVT' => 'BV', + 'BRA' => 'BR', + 'IOT' => 'IO', + 'BRN' => 'BN', + 'BGR' => 'BG', + 'BFA' => 'BF', + 'BDI' => 'BI', + 'CPV' => 'CV', + 'KHM' => 'KH', + 'CMR' => 'CM', + 'CAN' => 'CA', + 'CYM' => 'KY', + 'CAF' => 'CF', + 'TCD' => 'TD', + 'CHL' => 'CL', + 'CHN' => 'CN', + 'CXR' => 'CX', + 'CCK' => 'CC', + 'COL' => 'CO', + 'COM' => 'KM', + 'COG' => 'CG', + 'COD' => 'CD', + 'COK' => 'CK', + 'CRI' => 'CR', + 'CIV' => 'CI', + 'HRV' => 'HR', + 'CUB' => 'CU', + 'CUW' => 'CW', + 'CYP' => 'CY', + 'CZE' => 'CZ', + 'DNK' => 'DK', + 'DJI' => 'DJ', + 'DMA' => 'DM', + 'DOM' => 'DO', + 'ECU' => 'EC', + 'EGY' => 'EG', + 'SLV' => 'SV', + 'GNQ' => 'GQ', + 'ERI' => 'ER', + 'EST' => 'EE', + 'SWZ' => 'SZ', + 'ETH' => 'ET', + 'FLK' => 'FK', + 'FRO' => 'FO', + 'FJI' => 'FJ', + 'FIN' => 'FI', + 'FRA' => 'FR', + 'GUF' => 'GF', + 'PYF' => 'PF', + 'ATF' => 'TF', + 'GAB' => 'GA', + 'GMB' => 'GM', + 'GEO' => 'GE', + 'DEU' => 'DE', + 'GHA' => 'GH', + 'GIB' => 'GI', + 'GRC' => 'GR', + 'GRL' => 'GL', + 'GRD' => 'GD', + 'GLP' => 'GP', + 'GUM' => 'GU', + 'GTM' => 'GT', + 'GGY' => 'GG', + 'GIN' => 'GN', + 'GNB' => 'GW', + 'GUY' => 'GY', + 'HTI' => 'HT', + 'HMD' => 'HM', + 'VAT' => 'VA', + 'HND' => 'HN', + 'HKG' => 'HK', + 'HUN' => 'HU', + 'ISL' => 'IS', + 'IND' => 'IN', + 'IDN' => 'ID', + 'IRN' => 'IR', + 'IRQ' => 'IQ', + 'IRL' => 'IE', + 'IMN' => 'IM', + 'ISR' => 'IL', + 'ITA' => 'IT', + 'JAM' => 'JM', + 'JPN' => 'JP', + 'JEY' => 'JE', + 'JOR' => 'JO', + 'KAZ' => 'KZ', + 'KEN' => 'KE', + 'KIR' => 'KI', + 'PRK' => 'KP', + 'KOR' => 'KR', + 'KWT' => 'KW', + 'KGZ' => 'KG', + 'LAO' => 'LA', + 'LVA' => 'LV', + 'LBN' => 'LB', + 'LSO' => 'LS', + 'LBR' => 'LR', + 'LBY' => 'LY', + 'LIE' => 'LI', + 'LTU' => 'LT', + 'LUX' => 'LU', + 'MAC' => 'MO', + 'MDG' => 'MG', + 'MWI' => 'MW', + 'MYS' => 'MY', + 'MDV' => 'MV', + 'MLI' => 'ML', + 'MLT' => 'MT', + 'MHL' => 'MH', + 'MTQ' => 'MQ', + 'MRT' => 'MR', + 'MUS' => 'MU', + 'MYT' => 'YT', + 'MEX' => 'MX', + 'FSM' => 'FM', + 'MDA' => 'MD', + 'MCO' => 'MC', + 'MNG' => 'MN', + 'MNE' => 'ME', + 'MSR' => 'MS', + 'MAR' => 'MA', + 'MOZ' => 'MZ', + 'MMR' => 'MM', + 'NAM' => 'NA', + 'NRU' => 'NR', + 'NPL' => 'NP', + 'NLD' => 'NL', + 'NCL' => 'NC', + 'NZL' => 'NZ', + 'NIC' => 'NI', + 'NER' => 'NE', + 'NGA' => 'NG', + 'NIU' => 'NU', + 'NFK' => 'NF', + 'MKD' => 'MK', + 'MNP' => 'MP', + 'NOR' => 'NO', + 'OMN' => 'OM', + 'PAK' => 'PK', + 'PLW' => 'PW', + 'PSE' => 'PS', + 'PAN' => 'PA', + 'PNG' => 'PG', + 'PRY' => 'PY', + 'PER' => 'PE', + 'PHL' => 'PH', + 'PCN' => 'PN', + 'POL' => 'PL', + 'PRT' => 'PT', + 'PRI' => 'PR', + 'QAT' => 'QA', + 'REU' => 'RE', + 'ROU' => 'RO', + 'RUS' => 'RU', + 'RWA' => 'RW', + 'BLM' => 'BL', + 'SHN' => 'SH', + 'KNA' => 'KN', + 'LCA' => 'LC', + 'MAF' => 'MF', + 'SPM' => 'PM', + 'VCT' => 'VC', + 'WSM' => 'WS', + 'SMR' => 'SM', + 'STP' => 'ST', + 'SAU' => 'SA', + 'SEN' => 'SN', + 'SRB' => 'RS', + 'SYC' => 'SC', + 'SLE' => 'SL', + 'SGP' => 'SG', + 'SXM' => 'SX', + 'SVK' => 'SK', + 'SVN' => 'SI', + 'SLB' => 'SB', + 'SOM' => 'SO', + 'ZAF' => 'ZA', + 'SGS' => 'GS', + 'SSD' => 'SS', + 'ESP' => 'ES', + 'LKA' => 'LK', + 'SDN' => 'SD', + 'SUR' => 'SR', + 'SJM' => 'SJ', + 'SWE' => 'SE', + 'CHE' => 'CH', + 'SYR' => 'SY', + 'TWN' => 'TW', + 'TJK' => 'TJ', + 'TZA' => 'TZ', + 'THA' => 'TH', + 'TLS' => 'TL', + 'TGO' => 'TG', + 'TKL' => 'TK', + 'TON' => 'TO', + 'TTO' => 'TT', + 'TUN' => 'TN', + 'TUR' => 'TR', + 'TKM' => 'TM', + 'TCA' => 'TC', + 'TUV' => 'TV', + 'UGA' => 'UG', + 'UKR' => 'UA', + 'ARE' => 'AE', + 'GBR' => 'GB', + 'USA' => 'US', + 'UMI' => 'UM', + 'URY' => 'UY', + 'UZB' => 'UZ', + 'VUT' => 'VU', + 'VEN' => 'VE', + 'VNM' => 'VN', + 'VGB' => 'VG', + 'VIR' => 'VI', + 'WLF' => 'WF', + 'ESH' => 'EH', + 'YEM' => 'YE', + 'ZMB' => 'ZM', + 'ZWE' => 'ZW', + ], +]; diff --git a/lib/InstallSchema.php b/lib/InstallSchema.php index 27f3291..4e98356 100755 --- a/lib/InstallSchema.php +++ b/lib/InstallSchema.php @@ -63,6 +63,10 @@ class InstallSchema `accept_language_raw` text DEFAULT NULL COMMENT 'Accept-Language 完整值', `judge_timing` text DEFAULT NULL COMMENT '判定用时 JSON', `fp_hdata` text DEFAULT NULL COMMENT '指纹 hdata 解码 JSON', + `api_by_request` text DEFAULT NULL COMMENT 'byApi 请求参数 JSON', + `api_by_response` text DEFAULT NULL COMMENT 'byApi 响应 JSON', + `api_risk_request` text DEFAULT NULL COMMENT 'byApiRisk 请求参数 JSON', + `api_risk_response` text DEFAULT NULL COMMENT 'byApiRisk 响应 JSON', `add_time` timestamp NOT NULL DEFAULT current_timestamp() COMMENT '日志记录时间', PRIMARY KEY (`id`), KEY `IP` (`IP`), diff --git a/lib/bootstrap.php b/lib/bootstrap.php index 0b541d4..4f2fb97 100755 --- a/lib/bootstrap.php +++ b/lib/bootstrap.php @@ -23,8 +23,11 @@ require_once __DIR__ . '/Cloak/PipelineTimer.php'; require_once __DIR__ . '/Cloak/ClientIpResolver.php'; require_once __DIR__ . '/Cloak/GeoIpCountryCache.php'; require_once __DIR__ . '/Cloak/GeoIpCountryResolver.php'; +require_once __DIR__ . '/Cloak/CountryCodeNormalizer.php'; require_once __DIR__ . '/Cloak/CountryAllowlist.php'; +require_once __DIR__ . '/Cloak/RiskSecondaryGate.php'; require_once __DIR__ . '/Cloak/VisitorLogSchema.php'; +require_once __DIR__ . '/Cloak/VisitorApiAudit.php'; require_once __DIR__ . '/Cloak/VisitorLogQueue.php'; require_once __DIR__ . '/Cloak/VisitorLogWorker.php'; require_once __DIR__ . '/Cloak/Pipeline/CheckPipeline.php'; diff --git a/lib_FLTSX.zip b/lib_FLTSX.zip deleted file mode 100755 index 20855554057b49b4e4c94ba2547ef508dce8ba08..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 92333 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 Zi4y>w<4RYwSmh3dL#iq3_VtF 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 z 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 VDj)!c!9;<-?Tj#392n)m{s*z%`f~sP diff --git a/table.php b/table.php index 71a8b84..963aaad 100755 --- a/table.php +++ b/table.php @@ -183,8 +183,32 @@ if(empty($_SESSION['password']) || $_SESSION['password'] != LOGIN_PASSWORD) { .cell-copy-link:hover { color: var(--log-primary-dark); } .cell-ip { font-family: 'SF Mono', 'Consolas', monospace; font-size: 12px; } .text-muted { color: #adb5bd; } - .fp-hdata-cell { display: flex; flex-direction: column; gap: 4px; max-width: 100%; } - .fp-hdata-summary { font-size: 11.5px; color: #475569; line-height: 1.35; } + .fp-hdata-cell { + display: flex; + flex-direction: row; + flex-wrap: wrap; + align-items: center; + gap: 4px 8px; + max-width: 100%; + min-height: 24px; + } + .fp-hdata-summary { + flex: 1 1 140px; + min-width: 0; + font-size: 11.5px; + color: #475569; + line-height: 1.35; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + } + .fp-hdata-actions { + display: inline-flex; + flex-wrap: wrap; + align-items: center; + gap: 4px; + flex: 0 0 auto; + } .fp-hdata-btn { display: inline-block; padding: 1px 8px; @@ -197,6 +221,28 @@ if(empty($_SESSION['password']) || $_SESSION['password'] != LOGIN_PASSWORD) { width: fit-content; } .fp-hdata-btn:hover { background: #d1ecf1; } + /* 指纹 / API 审计列:解除 layui 固定行高,避免「判定详情」等按钮被裁切 */ + .log-table-wrap .layui-table-body td[data-field="fp_hdata_text"], + .log-table-wrap .layui-table-body td[data-field="api_by_request_text"], + .log-table-wrap .layui-table-body td[data-field="api_by_response_text"], + .log-table-wrap .layui-table-body td[data-field="api_risk_request_text"], + .log-table-wrap .layui-table-body td[data-field="api_risk_response_text"] { + height: auto !important; + vertical-align: top; + } + .log-table-wrap .layui-table-body td[data-field="fp_hdata_text"] > .layui-table-cell, + .log-table-wrap .layui-table-body td[data-field="api_by_request_text"] > .layui-table-cell, + .log-table-wrap .layui-table-body td[data-field="api_by_response_text"] > .layui-table-cell, + .log-table-wrap .layui-table-body td[data-field="api_risk_request_text"] > .layui-table-cell, + .log-table-wrap .layui-table-body td[data-field="api_risk_response_text"] > .layui-table-cell { + height: auto !important; + max-height: none !important; + white-space: normal !important; + overflow: visible !important; + line-height: 1.35; + padding-top: 7px !important; + padding-bottom: 7px !important; + } .fp-risk-explain { font-size: 13px; line-height: 1.55; color: #2c3e50; } .fp-risk-explain-head { display: flex; align-items: center; justify-content: space-between; margin-bottom: 12px; } .fp-risk-tag { font-size: 12px; padding: 2px 10px; border-radius: 999px; background: #eef2ff; color: #3730a3; font-weight: 600; } @@ -455,6 +501,26 @@ layui.use(function(){ return '' + short + ''; } + function formatJsonPretty(str) { + try { + return JSON.stringify(JSON.parse(str), null, 2); + } catch (e) { + return str; + } + } + + function cellApiAudit(val, title) { + if (val == null || val === '' || val === '-') { + return ''; + } + var text = String(val); + var short = text.length > 40 ? text.slice(0, 40) + '…' : text; + return '
' + + '' + escapeHtml(short) + '' + + '查看 JSON' + + '
'; + } + function cellFpHdata(d) { if (!d.fp_hdata && !d.fp_hdata_text) { return ''; @@ -465,14 +531,16 @@ layui.use(function(){ if (summary) { html += '' + escapeHtml(summary.length > 48 ? summary.slice(0, 48) + '…' : summary) + ''; } + html += ''; if (d.fp_hdata_explain_html) { html += '判定详情'; window.__fpExplainCache = window.__fpExplainCache || {}; window.__fpExplainCache[d.id] = d.fp_hdata_explain_html; - } else if (d.fp_hdata || d.fp_hdata_text) { + } + if (d.fp_hdata || d.fp_hdata_text) { html += '原始 hdata'; } - html += '
'; + html += '
'; return html; } @@ -502,6 +570,10 @@ layui.use(function(){ { field: 'http_referer', title: 'HTTP-Referer', width: 260, defaultVisible: false, templet: function(d){ return cellLinkEllipsis(d.http_referer, LINK_CELL_MAX); } }, { field: 'accept_language_raw', title: 'Accept-Language', width: 220, defaultVisible: false, templet: function(d){ return cellEllipsis(d.accept_language_raw, 32); } }, { field: 'fp_hdata_text', title: '指纹 hdata', width: 360, defaultVisible: false, templet: function(d){ return cellFpHdata(d); } }, + { field: 'api_by_request_text', title: 'byApi 请求参数', width: 300, defaultVisible: false, templet: function(d){ return cellApiAudit(d.api_by_request_text, 'byApi 请求参数 #' + d.id); } }, + { field: 'api_by_response_text', title: 'byApi 返回值', width: 300, defaultVisible: false, templet: function(d){ return cellApiAudit(d.api_by_response_text, 'byApi 返回值 #' + d.id); } }, + { field: 'api_risk_request_text', title: 'byApiRisk 请求参数', width: 300, defaultVisible: false, templet: function(d){ return cellApiAudit(d.api_risk_request_text, 'byApiRisk 请求参数 #' + d.id); } }, + { field: 'api_risk_response_text', title: 'byApiRisk 返回值', width: 300, defaultVisible: false, templet: function(d){ return cellApiAudit(d.api_risk_response_text, 'byApiRisk 返回值 #' + d.id); } }, ]; var COLUMN_DEF_MAP = {}; @@ -598,8 +670,27 @@ layui.use(function(){ return [cols]; } + function fixRichTableCellHeights() { + var fields = ['fp_hdata_text', 'api_by_request_text', 'api_by_response_text', 'api_risk_request_text', 'api_risk_response_text']; + fields.forEach(function(field) { + $('.log-table-wrap .layui-table-body td[data-field="' + field + '"]').each(function() { + var $cell = $(this).children('.layui-table-cell'); + $cell.css({ height: 'auto', whiteSpace: 'normal', overflow: 'visible' }); + $(this).css('height', 'auto'); + }); + }); + } + function reloadTableCols() { - table.reload(TABLE_ID, { cols: buildCols(colConfig) }); + table.reload(TABLE_ID, { + cols: buildCols(colConfig), + done: function(res, curr, count) { + if (typeof count === 'number') { + $("#total_nums").text(count); + } + fixRichTableCellHeights(); + } + }); } function renderColSettingsList() { @@ -736,8 +827,15 @@ layui.use(function(){ return 'color:#856404;background-color:#fff8e6;'; } }, + lineStyle: function(row) { + if (row.fp_hdata || row.fp_hdata_text || row.fp_hdata_explain_html) { + return 'height:auto;'; + } + return ''; + }, done: function(res, curr, count, origin){ $("#total_nums").text(count); + fixRichTableCellHeights(); }, }); @@ -758,12 +856,16 @@ layui.use(function(){ } var full = this.getAttribute('data-full') || ''; if (full) { + var popupTitle = this.getAttribute('data-title') || '指纹 hdata'; + var body = this.classList.contains('fp-hdata-btn-json') + ? escapeHtml(formatJsonPretty(full)) + : escapeHtml(full); layer.open({ type: 1, - title: '指纹 hdata', + title: popupTitle, area: ['680px', '70vh'], shadeClose: true, - content: '
' + escapeHtml(full) + '
' + content: '
' + body + '
' }); } }); diff --git a/tools/verify_geoip.php b/tools/verify_geoip.php index 609328a..808a738 100644 --- a/tools/verify_geoip.php +++ b/tools/verify_geoip.php @@ -51,6 +51,13 @@ if ($tests['resolver_available']) { if (!$tests['allowlist_us'] || !$tests['allowlist_cn']) { $ok = false; } + + $tests['normalize_iso2'] = CountryCodeNormalizer::toAlpha2('us') === 'US'; + $tests['normalize_name'] = CountryCodeNormalizer::toAlpha2('United States') === 'US'; + $tests['allowlist_name'] = CountryAllowlist::isAllowed('United Kingdom', CountryAllowlist::parse('GB,US')); + if (!$tests['normalize_iso2'] || !$tests['normalize_name'] || !$tests['allowlist_name']) { + $ok = false; + } } echo json_encode([