mirror of
https://github.com/hotyue/IP-Sentinel.git
synced 2026-05-10 17:52:41 +08:00
Compare commits
10 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
16b6c3f20a | ||
|
|
e3750f4565 | ||
|
|
d3face9621 | ||
|
|
aeeb9e1a43 | ||
|
|
09c6bab04a | ||
|
|
2e73aa8833 | ||
|
|
03d88f4856 | ||
|
|
3cab2b2379 | ||
|
|
87faeae8f7 | ||
|
|
19f0bb7c36 |
31
README.md
31
README.md
@@ -1,5 +1,9 @@
|
||||
# 🛡️ IP-Sentinel (分布式 IP 哨兵集群)
|
||||
|
||||

|
||||

|
||||

|
||||
|
||||
> **一个极度轻量、零感知、支持中枢遥控的 VPS IP 自动化养护与区域纠偏引擎。**
|
||||
|
||||
📢 官方战术交流频道: 🛰️ [IP-Sentinel Matrix](https://t.me/IP_Sentinel_Matrix)
|
||||
@@ -8,13 +12,15 @@
|
||||
|
||||
## ✨ 核心极客特性
|
||||
|
||||
* 🗺️ **全球拓扑矩阵 (Global Nexus)**:**v3.0.0 新特性**。引入动态 `map.json` 索引中心与多级地理架构 (国家-省州-城市)。安装脚本全自动解析云端地图,支持无限扩展全球节点,真正实现“按图索骥”。
|
||||
* ☁️ **云端中枢 (Public Master)**:引入官方公共机器人 [@OmniBeacon_bot](https://t.me/OmniBeacon_bot),新手无需部署 Master 司令部,一键回车即可接入全球养护矩阵,极大降低入伍门槛。
|
||||
* 🗺️ **全球拓扑矩阵 (Global Nexus)**:**v3.1 跨洲际跃升**。守护版图现已横跨亚、欧、美三大洲(**美、日、英、德、法、新、港**)。为每个国家注入极其硬核的“原生本地化”搜索词库与本土高权重站点(如政府、权威媒体、高铁网),真正实现“拟真融入”。
|
||||
* ☁️ **云端中枢 (Public Master)**:引入官方公共机器人 [@OmniBeacon_bot](https://t.me/OmniBeacon_bot),新手无需部署 Master 司令部,部署 Agent 时一键回车即可调用官方加密网关,30 秒极速入伍!
|
||||
* 🧠 **分布式中枢 (Master-Agent)**:对于硬核极客,支持私有化部署。一台 Master 主控集成 SQLite 数据库,统管无数台 Agent 边缘节点,确保数据绝对私有。
|
||||
* 🎮 **TG 战术面板 (Command Center)**:无需记忆繁琐命令,原生 Inline Keyboard 按钮驱动。支持一键调出节点列表、一键下发伪装指令、一键索要精准战报、**毫秒级抓取实时运行日志**。
|
||||
* 🛡️ **NAT 穿透与安全网关 (NAT-Friendly)**:边缘节点采用 Python3 极轻量 Webhook 监听,**完全自定义通信端口**,完美支持受限 NAT 小鸡。独创 TG 转发授权机制,杜绝野生节点恶意接入。
|
||||
* 🔒 **叹息之墙 (Zero-Trust HMAC)**:**v3.1 核心重构**。全面废弃明文 Token,底层通讯引入 `时间戳 + HMAC-SHA256` 军用级动态签名。指令有效期仅 60 秒(阅后即焚),彻底免疫中间人抓包、重放攻击与端口爆破。
|
||||
* 🛡️ **工业级并发与自净引擎**:底层 Webhook 采用多线程模型彻底免疫慢速耗尽攻击;独创“智能清道夫”逻辑,覆盖安装/升级时自动绞杀僵尸进程与冗余定时任务,绝对纯净,告别玄学冲突。
|
||||
* 🎮 **TG 战术面板 (Command Center)**:无需记忆繁琐命令,全 Inline Keyboard 交互。支持一键下发伪装指令、一键索要精准战报、**毫秒级抓取边缘节点实时运行日志**。
|
||||
* 👻 **高仿真人类行为 (Human-Like)**:摒弃死板的 Ping/Curl,引入单次会话指纹锁定、10 米级 GPS 坐标微抖动、以及 60~150 秒的真实阅读停顿拉伸,完美避开 AI 封控。
|
||||
* 📡 **OTA 静默进化 (Smart Updates)**:系统每周日凌晨自动从云端拉取最新的“热搜词汇”和“真实设备指纹池”,确保养护行为与时俱进、永不过时。
|
||||
* 👁️🗨️ **玻璃房透明遥测 (Glasshouse Telemetry)**:**v3.1.2 全新上线**。引入基于 Cloudflare Workers 的全透明计数中枢,首页动态徽章实时展示全球真实装机与调用量。**绝对零隐私收集**,仅作原子累加,底层网关源码全开源,接受全网极客审计。
|
||||
* ⚡ **丝滑战术交互 (Seamless UI)**:司令部交互面板像素级打磨。新节点发送暗号入伍成功后,司令部将**无缝零延迟自动呼出**最新的活跃节点阵列面板,彻底免除重复输入命令的繁琐,掌控感拉满。
|
||||
|
||||
## 📂 项目架构 (Monorepo)
|
||||
|
||||
@@ -24,16 +30,17 @@
|
||||
📦 IP-Sentinel
|
||||
┣ 📂 master/ # 🧠 司令部:SQLite 存储、TG 监听与 Webhook 调度中心
|
||||
┣ 📂 core/ # 🛡️ 边缘哨兵:Webhook 被动监听、高拟真养护引擎
|
||||
┗ 📂 data/ # 🗂️ 全球数据规则库 (v3.0 全新拓扑)
|
||||
┣ 📜 map.json # 🌐 全球区域索引大脑 (Master Index)
|
||||
┣ 📂 regions/ # 🧊 冷数据:按 [国家/省州/城市] 深度细分的 LBS 锚点
|
||||
┣ 📂 keywords/ # 🔥 热数据:按国家归类的动态搜索词库 (OTA 自动更新)
|
||||
┗ 📜 user_agents.txt # 🔥 热数据:全局真实设备指纹池
|
||||
┣ 📂 data/ # 🗂️ 全球数据规则库 (动态拓扑)
|
||||
┃ ┣ 📜 map.json # 🌐 全球区域索引大脑 (Master Index)
|
||||
┃ ┣ 📂 regions/ # 🧊 冷数据:按 [国家/省州/城市] 深度细分的 LBS 锚点
|
||||
┃ ┣ 📂 keywords/ # 🔥 热数据:按国家归类的动态搜索词库 (OTA 自动更新)
|
||||
┃ ┗ 📜 user_agents.txt # 🔥 热数据:全局真实设备指纹池
|
||||
┗ 📂 telemetry/ # 👁️🗨️ 玻璃房计划:Cloudflare Workers 透明计数器网关源码
|
||||
```
|
||||
|
||||
## 🚀 极速部署 (Quick Start)
|
||||
|
||||
v3.0.0 提供了两种接入模式,请根据您的战术需求选择:
|
||||
v3.1.x 提供了两种接入模式,请根据您的战术需求选择:
|
||||
|
||||
### 🔹 模式 A:官方公共模式 (最简、推荐)
|
||||
**适合不想折腾、只想快速养护 IP 的新兵。**
|
||||
@@ -64,7 +71,7 @@ bash <(curl -sL https://raw.githubusercontent.com/hotyue/IP-Sentinel/main/core/i
|
||||
|
||||
|
||||
🗑️ 一键无痕卸载
|
||||
如果你需要清理某个边缘节点,只需重新运行 core/install.sh 并选择 [3],或直接在节点终端执行:
|
||||
如果你需要清理某个边缘节点,只需重新运行 `core/install.sh` 并选择 **[2]**,或直接在节点终端执行:
|
||||
|
||||
```Bash
|
||||
bash /opt/ip_sentinel/core/uninstall.sh
|
||||
|
||||
@@ -41,7 +41,8 @@ if [ -n "$AGENT_IP" ]; then
|
||||
|
||||
# 只有当这是第一次运行,或者公网 IP 发生变动时,才发送 Telegram 申请
|
||||
if [ "$AGENT_IP" != "$LAST_IP" ]; then
|
||||
REG_MSG="👋 **[边缘节点接入申请]**%0A节点: \`${NODE_NAME}\`%0A地址: \`${AGENT_IP}:${AGENT_PORT}\`%0A%0A⚠️ **安全验证**: 为防止非法节点接入,请长按复制下方代码,并**发送给我**以完成最终授权录入:%0A%0A\`#REGISTER#|${NODE_NAME}|${AGENT_IP}|${AGENT_PORT}\`"
|
||||
# V3.1.3 协议升级: 在底部暗号中精准嵌入 ${REGION_CODE} 大区标识
|
||||
REG_MSG="👋 **[边缘节点接入申请]**%0A大区: \`${REGION_CODE}\`%0A节点: \`${NODE_NAME}\`%0A地址: \`${AGENT_IP}:${AGENT_PORT}\`%0A%0A⚠️ **安全验证**: 为防止非法节点接入,请长按复制下方代码,并**发送给我**以完成最终授权录入:%0A%0A\`#REGISTER#|${REGION_CODE}|${NODE_NAME}|${AGENT_IP}|${AGENT_PORT}\`"
|
||||
|
||||
curl -s -m 5 -X POST "${TG_API_URL}" \
|
||||
-d "chat_id=${CHAT_ID}" \
|
||||
|
||||
@@ -167,7 +167,7 @@ if [[ "$TG_CHOICE" =~ ^[Yy]$ ]]; then
|
||||
|
||||
if [ -z "$USER_TOKEN" ]; then
|
||||
TG_TOKEN="OFFICIAL_GATEWAY_MODE"
|
||||
TG_API_URL="https://omni-gateway.yuezhongjun.workers.dev"
|
||||
TG_API_URL="https://omni-gateway.samanthaestime296.workers.dev"
|
||||
echo -e "\033[32m✅ 已自动连接官方安全网关 (@OmniBeacon_bot)。\033[0m"
|
||||
echo -e "\033[33m👉 请确保您已关注官方机器人并发送过 /start,否则将无法接收消息。\033[0m"
|
||||
else
|
||||
@@ -360,6 +360,11 @@ if [[ -n "$TG_TOKEN" ]] && [[ -n "$CHAT_ID" ]]; then
|
||||
# 每天早上 8 点发送昨天的统计战报
|
||||
echo "0 8 * * * ${INSTALL_DIR}/core/tg_report.sh >/dev/null 2>&1" >> /tmp/cron_backup
|
||||
|
||||
# [v3.0.1新增修改 3: 删除原来的 curl 取 IP,直接使用我们上方锁定的 BIND_IP]
|
||||
# 并提前写入 IP 缓存,彻底阻断 agent_daemon 首次启动时的重复推送
|
||||
# [修复竞态]: 提前写入 IP 缓存,彻底阻断 agent_daemon 首次启动时的抢跑推送
|
||||
echo "$BIND_IP" > "${INSTALL_DIR}/core/.last_ip"
|
||||
|
||||
# 双保险守护进程看门狗
|
||||
echo "@reboot nohup bash ${INSTALL_DIR}/core/agent_daemon.sh >/dev/null 2>&1 &" >> /tmp/cron_backup
|
||||
echo "* * * * * nohup bash ${INSTALL_DIR}/core/agent_daemon.sh >/dev/null 2>&1 &" >> /tmp/cron_backup
|
||||
@@ -373,14 +378,10 @@ rm -f /tmp/cron_backup
|
||||
|
||||
if [[ -n "$TG_TOKEN" ]] && [[ -n "$CHAT_ID" ]]; then
|
||||
echo -e "\n📡 正在向指挥部发送注册暗号..."
|
||||
|
||||
# [v3.0.1新增修改 3: 删除原来的 curl 取 IP,直接使用我们上方锁定的 BIND_IP]
|
||||
# 并提前写入 IP 缓存,彻底阻断 agent_daemon 首次启动时的重复推送
|
||||
echo "$BIND_IP" > "${INSTALL_DIR}/core/.last_ip"
|
||||
|
||||
# 构造注册暗号 (使用带 [] 装甲的 BIND_IP,防止 Master 端解析错误)
|
||||
|
||||
# 构造注册暗号 (V3.1.3 协议升级: 携带 REGION_CODE 大区标识)
|
||||
NODE_NAME=$(hostname | cut -c 1-15)
|
||||
REG_MSG="#REGISTER#|${NODE_NAME}|${BIND_IP}|${AGENT_PORT}"
|
||||
REG_MSG="#REGISTER#|${REGION_CODE}|${NODE_NAME}|${BIND_IP}|${AGENT_PORT}"
|
||||
|
||||
# 执行主动推送
|
||||
PUSH_RESULT=$(curl -s -X POST "${TG_API_URL}" \
|
||||
|
||||
@@ -3,4 +3,7 @@ S&P 500 stock chart
|
||||
local coffee shops near me
|
||||
latest tech news
|
||||
California traffic updates
|
||||
AI startups in Silicon Valley
|
||||
AI startups in Silicon ValleySan Jose weather this weekend
|
||||
Silicon Valley tech news
|
||||
best tacos in San Jose
|
||||
Apple park visitor center hours
|
||||
|
||||
@@ -11,7 +11,8 @@
|
||||
"id": "CA",
|
||||
"name": "California (加州)",
|
||||
"cities": [
|
||||
{ "id": "Los_Angeles", "name": "Los Angeles (洛杉矶)" }
|
||||
{ "id": "Los_Angeles", "name": "Los Angeles (洛杉矶)" },
|
||||
{ "id": "San_Jose", "name": "San Jose (圣何塞)" }
|
||||
]
|
||||
}
|
||||
]
|
||||
|
||||
21
data/regions/US/CA/San_Jose.json
Normal file
21
data/regions/US/CA/San_Jose.json
Normal file
@@ -0,0 +1,21 @@
|
||||
{
|
||||
"region_name": "United States - San Jose",
|
||||
"google_module": {
|
||||
"base_lat": 37.3382,
|
||||
"base_lon": -121.8863,
|
||||
"lang_params": "hl=en&gl=US",
|
||||
"valid_url_suffix": "com"
|
||||
},
|
||||
"trust_module": {
|
||||
"white_urls": [
|
||||
"https://en.wikipedia.org/wiki/Special:Random",
|
||||
"https://www.yahoo.com/",
|
||||
"https://www.target.com/",
|
||||
"https://www.npr.org/",
|
||||
"https://www.weather.com/",
|
||||
"https://www.amazon.com/",
|
||||
"https://www.cdc.gov/",
|
||||
"https://www.mercurynews.com/"
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -9,7 +9,7 @@ CONF="/opt/ip_sentinel_master/master.conf"
|
||||
[ ! -f "$CONF" ] && exit 1
|
||||
source "$CONF"
|
||||
|
||||
OFFSET_FILE="/tmp/tg_master_offset"
|
||||
OFFSET_FILE="${MASTER_DIR}/.tg_offset"
|
||||
[[ -f $OFFSET_FILE ]] || echo "0" > $OFFSET_FILE
|
||||
|
||||
# --- 工具函数 ---
|
||||
@@ -54,6 +54,11 @@ generate_signed_url() {
|
||||
}
|
||||
# ========================================================================
|
||||
|
||||
# ================== [v3.1.3 核心: 数据库结构无损热升级] ==================
|
||||
# 自动探测并增加 region 字段,屏蔽已存在的报错,保护老节点数据
|
||||
db_exec "ALTER TABLE nodes ADD COLUMN region TEXT DEFAULT 'UNKNOWN';" 2>/dev/null
|
||||
# ========================================================================
|
||||
|
||||
# --- 核心轮询循环 ---
|
||||
while true; do
|
||||
OFFSET=$(cat $OFFSET_FILE)
|
||||
@@ -79,33 +84,59 @@ while true; do
|
||||
fi
|
||||
|
||||
# ==========================================
|
||||
# 1. 节点注册通道 (v3.0.1 终极防注入补丁)
|
||||
# 1. 节点注册通道 (V3.1.3 大区拓扑升级版)
|
||||
# ==========================================
|
||||
if [[ "$TEXT" == *"#REGISTER#"* ]]; then
|
||||
REG_LINE=$(echo "$TEXT" | grep "#REGISTER#" | head -n 1 | tr -d '\` ')
|
||||
IFS='|' read -r MAGIC RAW_NODE RAW_IP RAW_PORT <<< "$REG_LINE"
|
||||
|
||||
# 🛡️ 强制字符白名单过滤:物理抹杀所有 SQL 注入特殊字符
|
||||
CHAT_ID=$(echo "$CHAT_ID" | tr -cd '0-9-') # ChatID 只能是数字和负号
|
||||
NODE_NAME=$(echo "$RAW_NODE" | tr -cd 'a-zA-Z0-9_.-' | cut -c 1-30) # 节点名限字母数字横杠下划线
|
||||
AGENT_IP=$(echo "$RAW_IP" | tr -cd 'a-zA-Z0-9.:\[\]-' | cut -c 1-50) # IP 格式限制
|
||||
AGENT_PORT=$(echo "$RAW_PORT" | tr -cd '0-9' | cut -c 1-5) # 端口只能是数字
|
||||
# V3.1.3 兼容性拆包: 判断是新版协议 (5个字段) 还是老版协议 (4个字段)
|
||||
FIELD_COUNT=$(echo "$REG_LINE" | awk -F'|' '{print NF}')
|
||||
if [ "$FIELD_COUNT" -ge 5 ]; then
|
||||
IFS='|' read -r MAGIC RAW_REGION RAW_NODE RAW_IP RAW_PORT <<< "$REG_LINE"
|
||||
else
|
||||
IFS='|' read -r MAGIC RAW_NODE RAW_IP RAW_PORT <<< "$REG_LINE"
|
||||
RAW_REGION="UNKNOWN"
|
||||
fi
|
||||
|
||||
# 🛡️ 强制字符白名单过滤:保留历史特征不变
|
||||
CHAT_ID=$(echo "$CHAT_ID" | tr -cd '0-9-')
|
||||
AGENT_REGION=$(echo "$RAW_REGION" | tr -cd 'a-zA-Z0-9' | cut -c 1-10) # 提取国家大区
|
||||
NODE_NAME=$(echo "$RAW_NODE" | tr -cd 'a-zA-Z0-9_.-' | cut -c 1-30)
|
||||
AGENT_IP=$(echo "$RAW_IP" | tr -cd 'a-zA-Z0-9.:\[\]-' | cut -c 1-50)
|
||||
AGENT_PORT=$(echo "$RAW_PORT" | tr -cd '0-9' | cut -c 1-5)
|
||||
|
||||
# ================== [v3.0.2 紧急加固: SSRF 内网隔离墙] ==================
|
||||
# 拒绝 127.x, 10.x, 192.168.x, 172.16~31.x 以及 IPv6 回环地址的注册
|
||||
if [[ "$AGENT_IP" =~ ^127\.|^10\.|^192\.168\.|^172\.(1[6-9]|2[0-9]|3[0-1])\.|^::1$|^localhost$ ]]; then
|
||||
send_msg "$CHAT_ID" "⛔ **安全拦截**:禁止注册内网或回环 IP,防止 SSRF 攻击渗透。"
|
||||
continue
|
||||
fi
|
||||
|
||||
# 异常拦截:如果核心字段被过滤成了空值,说明是恶意请求,直接抛弃
|
||||
if [ -z "$NODE_NAME" ] || [ -z "$AGENT_IP" ] || [ -z "$AGENT_PORT" ] || [ -z "$CHAT_ID" ]; then
|
||||
send_msg "$CHAT_ID" "⛔ **安全拦截**:检测到非法注册载荷,请求已拒绝。"
|
||||
continue
|
||||
fi
|
||||
|
||||
db_exec "INSERT INTO nodes (chat_id, node_name, agent_ip, agent_port, last_seen) VALUES ('$CHAT_ID', '$NODE_NAME', '$AGENT_IP', '$AGENT_PORT', CURRENT_TIMESTAMP) ON CONFLICT(chat_id, node_name) DO UPDATE SET agent_ip='$AGENT_IP', agent_port='$AGENT_PORT', last_seen=CURRENT_TIMESTAMP;"
|
||||
# 入库时追加 region 字段
|
||||
db_exec "INSERT INTO nodes (chat_id, node_name, agent_ip, agent_port, last_seen, region) VALUES ('$CHAT_ID', '$NODE_NAME', '$AGENT_IP', '$AGENT_PORT', CURRENT_TIMESTAMP, '$AGENT_REGION') ON CONFLICT(chat_id, node_name) DO UPDATE SET agent_ip='$AGENT_IP', agent_port='$AGENT_PORT', last_seen=CURRENT_TIMESTAMP, region='$AGENT_REGION';"
|
||||
send_msg "$CHAT_ID" "✅ 司令部已确认!节点接入成功: \`$NODE_NAME\` ($AGENT_IP:$AGENT_PORT)"
|
||||
|
||||
# ================== [v3.1.3 丝滑连招: 直接呼出全球大区雷达] ==================
|
||||
REGION_DATA=$(db_exec "SELECT region, COUNT(*) FROM nodes WHERE chat_id='$CHAT_ID' GROUP BY region;")
|
||||
if [ -n "$REGION_DATA" ]; then
|
||||
BTNS="["
|
||||
while IFS='|' read -r REGION_NAME NODE_COUNT; do
|
||||
[ -z "$REGION_NAME" ] && REGION_NAME="UNKNOWN"
|
||||
FLAG="🌐"
|
||||
case "$REGION_NAME" in
|
||||
"US") FLAG="🇺🇸" ;; "JP") FLAG="🇯🇵" ;; "HK") FLAG="🇭🇰" ;;
|
||||
"SG") FLAG="🇸🇬" ;; "UK"|"GB") FLAG="🇬🇧" ;; "DE") FLAG="🇩🇪" ;; "FR") FLAG="🇫🇷" ;;
|
||||
esac
|
||||
BTNS="$BTNS[{\"text\":\"$FLAG $REGION_NAME ($NODE_COUNT 台)\",\"callback_data\":\"region:$REGION_NAME\"}],"
|
||||
done <<< "$REGION_DATA"
|
||||
BTNS="${BTNS%,}]"
|
||||
send_ui "$CHAT_ID" "🌍 **全视界战略雷达**\n请选择要检阅的战区:" "$BTNS"
|
||||
fi
|
||||
# ========================================================================
|
||||
|
||||
continue
|
||||
fi
|
||||
|
||||
@@ -149,16 +180,56 @@ while true; do
|
||||
# ====================================================================
|
||||
|
||||
"list_nodes")
|
||||
NODE_LIST=$(db_exec "SELECT node_name FROM nodes WHERE chat_id='$CHAT_ID';")
|
||||
if [ -z "$NODE_LIST" ]; then
|
||||
# 【V3.1.3】一级菜单:大区聚合并列出数量
|
||||
REGION_DATA=$(db_exec "SELECT region, COUNT(*) FROM nodes WHERE chat_id='$CHAT_ID' GROUP BY region;")
|
||||
if [ -z "$REGION_DATA" ]; then
|
||||
send_msg "$CHAT_ID" "⚠️ 您名下暂无在线节点,请先在边缘机执行部署。"
|
||||
else
|
||||
BTNS="["
|
||||
for N in $NODE_LIST; do
|
||||
BTNS="$BTNS[{\"text\":\"🖥️ $N\",\"callback_data\":\"manage:$N\"}],"
|
||||
done
|
||||
while IFS='|' read -r REGION_NAME NODE_COUNT; do
|
||||
[ -z "$REGION_NAME" ] && REGION_NAME="UNKNOWN"
|
||||
FLAG="🌐"
|
||||
case "$REGION_NAME" in
|
||||
"US") FLAG="🇺🇸" ;; "JP") FLAG="🇯🇵" ;; "HK") FLAG="🇭🇰" ;;
|
||||
"SG") FLAG="🇸🇬" ;; "UK"|"GB") FLAG="🇬🇧" ;; "DE") FLAG="🇩🇪" ;; "FR") FLAG="🇫🇷" ;;
|
||||
esac
|
||||
BTNS="$BTNS[{\"text\":\"$FLAG $REGION_NAME ($NODE_COUNT 台)\",\"callback_data\":\"region:$REGION_NAME\"}],"
|
||||
done <<< "$REGION_DATA"
|
||||
BTNS="${BTNS%,}]"
|
||||
send_ui "$CHAT_ID" "🔍 您名下的活跃节点:" "$BTNS"
|
||||
send_ui "$CHAT_ID" "🌍 **全视界战略雷达**\n请选择要检阅的战区:" "$BTNS"
|
||||
fi
|
||||
;;
|
||||
|
||||
region:*)
|
||||
# 【V3.1.3】二级菜单:目标大区下的节点双列排版
|
||||
TARGET_REGION=$(echo "${TEXT#*:}" | tr -cd 'a-zA-Z0-9')
|
||||
CHAT_ID=$(echo "$CHAT_ID" | tr -cd '0-9-')
|
||||
|
||||
NODE_LIST=$(db_exec "SELECT node_name FROM nodes WHERE chat_id='$CHAT_ID' AND region='$TARGET_REGION';")
|
||||
if [ -z "$NODE_LIST" ]; then
|
||||
send_msg "$CHAT_ID" "⚠️ 该战区下暂无可用节点。"
|
||||
else
|
||||
BTNS="["
|
||||
COL=0
|
||||
ROW_STR="["
|
||||
for N in $NODE_LIST; do
|
||||
ROW_STR="$ROW_STR{\"text\":\"🖥️ $N\",\"callback_data\":\"manage:$N\"},"
|
||||
COL=$((COL+1))
|
||||
if [ $COL -eq 2 ]; then
|
||||
ROW_STR="${ROW_STR%,}]"
|
||||
BTNS="$BTNS$ROW_STR,"
|
||||
COL=0
|
||||
ROW_STR="["
|
||||
fi
|
||||
done
|
||||
# 如果是奇数,补齐最后的尾巴
|
||||
if [ $COL -eq 1 ]; then
|
||||
ROW_STR="${ROW_STR%,}]"
|
||||
BTNS="$BTNS$ROW_STR,"
|
||||
fi
|
||||
# 添加返回上级大区雷达的按钮
|
||||
BTNS="$BTNS[{\"text\":\"⬅️ 返回全球战区分布\",\"callback_data\":\"list_nodes\"}]]"
|
||||
send_ui "$CHAT_ID" "📍 **[$TARGET_REGION] 战区哨兵矩阵**\n请下达控制指令:" "$BTNS"
|
||||
fi
|
||||
;;
|
||||
|
||||
@@ -166,7 +237,7 @@ while true; do
|
||||
# 🛡️ 强制过滤节点名,防止面板渲染时发生 XSS 或注入
|
||||
TARGET_NODE=$(echo "${TEXT#*:}" | tr -cd 'a-zA-Z0-9_.-')
|
||||
# 【核心升级】拆分下发按钮,精准对应 Google 与 Trust 两个模块,并排版为 3 行 2 列
|
||||
BTNS="[[{\"text\":\"📍 Google 纠偏\",\"callback_data\":\"google:$TARGET_NODE\"}, {\"text\":\"🛡️ 信用净化\",\"callback_data\":\"trust:$TARGET_NODE\"}], [{\"text\":\"📜 实时日志\",\"callback_data\":\"log:$TARGET_NODE\"}, {\"text\":\"📊 统计战报\",\"callback_data\":\"report:$TARGET_NODE\"}], [{\"text\":\"🗑️ 剔除失联节点\",\"callback_data\":\"del:$TARGET_NODE\"}, {\"text\":\"⬅️ 返回主列表\",\"callback_data\":\"list_nodes\"}]]"
|
||||
BTNS="[[{\"text\":\"📍 Google 纠偏\",\"callback_data\":\"google:$TARGET_NODE\"}, {\"text\":\"🛡️ 信用净化\",\"callback_data\":\"trust:$TARGET_NODE\"}], [{\"text\":\"📜 实时日志\",\"callback_data\":\"log:$TARGET_NODE\"}, {\"text\":\"📊 统计战报\",\"callback_data\":\"report:$TARGET_NODE\"}], [{\"text\":\"🗑️ 剔除失联节点\",\"callback_data\":\"del:$TARGET_NODE\"}, {\"text\":\"⬅️ 返回大区目录\",\"callback_data\":\"list_nodes\"}]]"
|
||||
send_ui "$CHAT_ID" "⚙️ **目标锁定**: \`$TARGET_NODE\`\n请选择战术动作:" "$BTNS"
|
||||
;;
|
||||
|
||||
@@ -178,16 +249,23 @@ while true; do
|
||||
db_exec "DELETE FROM nodes WHERE chat_id='$CHAT_ID' AND node_name='$TARGET_NODE';"
|
||||
send_msg "$CHAT_ID" "🗑️ 节点 \`$TARGET_NODE\` 的档案已从司令部彻底销毁!"
|
||||
|
||||
NODE_LIST=$(db_exec "SELECT node_name FROM nodes WHERE chat_id='$CHAT_ID';")
|
||||
if [ -z "$NODE_LIST" ]; then
|
||||
# 剔除后直接返回上级一级雷达菜单
|
||||
REGION_DATA=$(db_exec "SELECT region, COUNT(*) FROM nodes WHERE chat_id='$CHAT_ID' GROUP BY region;")
|
||||
if [ -z "$REGION_DATA" ]; then
|
||||
send_msg "$CHAT_ID" "⚠️ 当前司令部已无任何节点挂载。"
|
||||
else
|
||||
BTNS="["
|
||||
for N in $NODE_LIST; do
|
||||
BTNS="$BTNS[{\"text\":\"🖥️ $N\",\"callback_data\":\"manage:$N\"}],"
|
||||
done
|
||||
while IFS='|' read -r REGION_NAME NODE_COUNT; do
|
||||
[ -z "$REGION_NAME" ] && REGION_NAME="UNKNOWN"
|
||||
FLAG="🌐"
|
||||
case "$REGION_NAME" in
|
||||
"US") FLAG="🇺🇸" ;; "JP") FLAG="🇯🇵" ;; "HK") FLAG="🇭🇰" ;;
|
||||
"SG") FLAG="🇸🇬" ;; "UK"|"GB") FLAG="🇬🇧" ;; "DE") FLAG="🇩🇪" ;; "FR") FLAG="🇫🇷" ;;
|
||||
esac
|
||||
BTNS="$BTNS[{\"text\":\"$FLAG $REGION_NAME ($NODE_COUNT 台)\",\"callback_data\":\"region:$REGION_NAME\"}],"
|
||||
done <<< "$REGION_DATA"
|
||||
BTNS="${BTNS%,}]"
|
||||
send_ui "$CHAT_ID" "🔍 刷新后的节点列表:" "$BTNS"
|
||||
send_ui "$CHAT_ID" "🌍 刷新后的全视界雷达:" "$BTNS"
|
||||
fi
|
||||
;;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user