Rename to hkt.sh

This commit is contained in:
mango
2026-03-21 01:10:53 +08:00
parent 76a263d0f9
commit 8f1171fe99
6676 changed files with 1724268 additions and 0 deletions

View File

@@ -0,0 +1,183 @@
import telebot
import requests
from telebot.types import InlineKeyboardMarkup, InlineKeyboardButton
BOT_TOKEN = "7741492900:AAG6M_faLy5JG7g0t2gBFj-sXtBIaBXQZHk"
ALLOWED_USERS = [165067365]
CF_API_TOKEN = "VfeGnC3v5McJ3sJ6bsjjhG0IhvOgY-5-v6lpYgH3"
bot = telebot.TeleBot(BOT_TOKEN)
ZONE_CACHE = {}
USER_STATE = {}
def get_zones():
headers = {"Authorization": f"Bearer {CF_API_TOKEN}"}
r = requests.get("https://api.cloudflare.com/client/v4/zones", headers=headers).json()
return r.get("result", [])
def get_zone_id(domain):
root = ".".join(domain.split(".")[-2:])
if root in ZONE_CACHE:
return ZONE_CACHE[root]
for z in get_zones():
if z["name"] == root:
ZONE_CACHE[root] = z["id"]
return z["id"]
return None
def is_authorized(uid):
return uid in ALLOWED_USERS
def main_menu():
markup = InlineKeyboardMarkup(row_width=2)
markup.add(
InlineKeyboardButton(' 添加记录', callback_data='add'),
InlineKeyboardButton('🗑 删除记录', callback_data='del'),
InlineKeyboardButton('☁️ 小黄云', callback_data='proxy'),
InlineKeyboardButton('📋 列出记录', callback_data='list')
)
return markup
def domain_menu(action):
zones = get_zones()
markup = InlineKeyboardMarkup(row_width=2)
for z in zones[:10]:
markup.add(InlineKeyboardButton(z['name'], callback_data=f"{action}:{z['name']}"))
markup.add(InlineKeyboardButton('🔙 返回', callback_data='back'))
return markup
@bot.message_handler(commands=['help', 'start'])
def start_cmd(message):
if not is_authorized(message.from_user.id): return
bot.send_message(message.chat.id, '🌐 CF DNS 管理', reply_markup=main_menu())
@bot.callback_query_handler(func=lambda c: True)
def callback_handler(call):
uid = call.from_user.id
if not is_authorized(uid): return
data = call.data
if data == 'back':
bot.edit_message_text('🌐 CF DNS 管理', call.message.chat.id, call.message.message_id, reply_markup=main_menu())
return
if data in ['add', 'del', 'proxy', 'list']:
bot.edit_message_text(f'选择域名:', call.message.chat.id, call.message.message_id, reply_markup=domain_menu(data))
return
if data.startswith('list:'):
domain = data.split(':')[1]
zone_id = get_zone_id(domain)
headers = {"Authorization": f"Bearer {CF_API_TOKEN}"}
r = requests.get(f"https://api.cloudflare.com/client/v4/zones/{zone_id}/dns_records", headers=headers).json()
records = r.get("result", [])
if not records:
txt = f'📋 {domain}\n\n无记录'
else:
lines = [f"{rec['name']} -> {rec['content']} ({'☁️' if rec['proxied'] else ''})" for rec in records[:15]]
txt = f'📋 {domain}\n\n' + '\n'.join(lines)
markup = InlineKeyboardMarkup()
markup.add(InlineKeyboardButton('🔙 返回', callback_data='back'))
bot.edit_message_text(txt, call.message.chat.id, call.message.message_id, reply_markup=markup)
return
if data.startswith('add:'):
domain = data.split(':')[1]
USER_STATE[uid] = {'action': 'add', 'domain': domain}
markup = InlineKeyboardMarkup()
markup.add(InlineKeyboardButton('🔙 取消', callback_data='back'))
bot.edit_message_text(f' 添加记录到 {domain}\n\n请输入: 子域名 IP\n例如: www 1.2.3.4', call.message.chat.id, call.message.message_id, reply_markup=markup)
return
if data.startswith('del:'):
domain = data.split(':')[1]
zone_id = get_zone_id(domain)
headers = {"Authorization": f"Bearer {CF_API_TOKEN}"}
r = requests.get(f"https://api.cloudflare.com/client/v4/zones/{zone_id}/dns_records", headers=headers).json()
records = r.get("result", [])
markup = InlineKeyboardMarkup(row_width=1)
for rec in records[:10]:
short = rec['name'].replace(f'.{domain}', '') if rec['name'] != domain else '@'
markup.add(InlineKeyboardButton(f"🗑 {short} -> {rec['content']}", callback_data=f"doit:{rec['id']}:{domain}"))
markup.add(InlineKeyboardButton('🔙 返回', callback_data='back'))
bot.edit_message_text(f'选择要删除的记录:', call.message.chat.id, call.message.message_id, reply_markup=markup)
return
if data.startswith('doit:'):
parts = data.split(':')
rec_id, domain = parts[1], parts[2]
zone_id = get_zone_id(domain)
headers = {"Authorization": f"Bearer {CF_API_TOKEN}"}
requests.delete(f"https://api.cloudflare.com/client/v4/zones/{zone_id}/dns_records/{rec_id}", headers=headers)
bot.answer_callback_query(call.id, '✅ 已删除')
bot.edit_message_text('🌐 CF DNS 管理', call.message.chat.id, call.message.message_id, reply_markup=main_menu())
return
if data.startswith('proxy:'):
domain = data.split(':')[1]
zone_id = get_zone_id(domain)
headers = {"Authorization": f"Bearer {CF_API_TOKEN}"}
r = requests.get(f"https://api.cloudflare.com/client/v4/zones/{zone_id}/dns_records", headers=headers).json()
records = r.get("result", [])
markup = InlineKeyboardMarkup(row_width=1)
for rec in records[:10]:
short = rec['name'].replace(f'.{domain}', '') if rec['name'] != domain else '@'
icon = '☁️' if rec['proxied'] else ''
markup.add(InlineKeyboardButton(f"{icon} {short} -> {rec['content']}", callback_data=f"toggle:{rec['id']}:{domain}"))
markup.add(InlineKeyboardButton('🔙 返回', callback_data='back'))
bot.edit_message_text(f'点击切换小黄云:', call.message.chat.id, call.message.message_id, reply_markup=markup)
return
if data.startswith('toggle:'):
parts = data.split(':')
rec_id, domain = parts[1], parts[2]
zone_id = get_zone_id(domain)
headers = {"Authorization": f"Bearer {CF_API_TOKEN}", "Content-Type": "application/json"}
r = requests.get(f"https://api.cloudflare.com/client/v4/zones/{zone_id}/dns_records/{rec_id}", headers=headers).json()
rec = r.get("result", {})
new_state = not rec.get('proxied', False)
requests.patch(f"https://api.cloudflare.com/client/v4/zones/{zone_id}/dns_records/{rec_id}", headers=headers, json={"proxied": new_state})
bot.answer_callback_query(call.id, f"✅ 小黄云已{'开启' if new_state else '关闭'}")
r = requests.get(f"https://api.cloudflare.com/client/v4/zones/{zone_id}/dns_records", headers=headers).json()
records = r.get("result", [])
markup = InlineKeyboardMarkup(row_width=1)
for rec in records[:10]:
short = rec['name'].replace(f'.{domain}', '') if rec['name'] != domain else '@'
icon = '☁️' if rec['proxied'] else ''
markup.add(InlineKeyboardButton(f"{icon} {short} -> {rec['content']}", callback_data=f"toggle:{rec['id']}:{domain}"))
markup.add(InlineKeyboardButton('🔙 返回', callback_data='back'))
bot.edit_message_reply_markup(call.message.chat.id, call.message.message_id, reply_markup=markup)
return
@bot.message_handler(func=lambda m: m.from_user.id in USER_STATE)
def handle_add(message):
uid = message.from_user.id
if not is_authorized(uid): return
state = USER_STATE.get(uid)
if not state or state['action'] != 'add': return
parts = message.text.strip().split()
if len(parts) < 2:
bot.reply_to(message, '格式错误,请输入: 子域名 IP')
return
sub, ip = parts[0], parts[1]
domain = state['domain']
del USER_STATE[uid]
zone_id = get_zone_id(domain)
if not zone_id:
bot.reply_to(message, f'找不到域名 {domain}')
return
name = f"{sub}.{domain}" if sub != '@' else domain
headers = {"Authorization": f"Bearer {CF_API_TOKEN}", "Content-Type": "application/json"}
data = {"type": "A", "name": name, "content": ip, "ttl": 1, "proxied": False}
r = requests.post(f"https://api.cloudflare.com/client/v4/zones/{zone_id}/dns_records", headers=headers, json=data).json()
if r.get("success"):
bot.reply_to(message, f'✅ 添加成功: {name} -> {ip}', reply_markup=main_menu())
else:
bot.reply_to(message, f'❌ 失败: {r.get("errors", [])}')
if __name__ == '__main__':
print('CF Bot 启动...')
bot.infinity_polling()