Files
Deploy-Laboratory/scripts/cloudflare-delete-acme-challenge-dns.sh
jack be97836e0d chore: 清理调试脚本并收敛到 Ansible 流程
移除已废弃的调试/验证脚本与空目录,统一文档与脚本说明到 ansible-playbook 的部署方式,避免失效引用和误用路径。

Made-with: Cursor
2026-03-23 19:18:55 +08:00

141 lines
4.6 KiB
Bash
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/usr/bin/env bash
# 批量删除 Cloudflare 中 _acme-challenge 相关的 DNS 记录
# 用法:环境变量 或 脚本内配置 二选一,环境变量优先
# CF_API_TOKEN=xxx ZONE_NAME=jackadam.top ./scripts/cloudflare-delete-acme-challenge-dns.sh [--dry-run]
# 或在下方配置中填写,直接运行 ./scripts/cloudflare-delete-acme-challenge-dns.sh [--dry-run]
set -e
# ---------- 脚本内配置(环境变量未设置时生效)----------
# Cloudflare API Token需 Zone → DNS → Read + Edit
# (勿将含真实 Token 的脚本提交到 Git
DEFAULT_CF_API_TOKEN=""
# 区域:填 ZONE_NAME 或 ZONE_ID 其一
DEFAULT_ZONE_NAME="jackadam.top"
DEFAULT_ZONE_ID=""
# ------------------------------------
# 环境变量优先于脚本配置
CF_API_TOKEN="${CF_API_TOKEN:-$DEFAULT_CF_API_TOKEN}"
ZONE_NAME="${ZONE_NAME:-$DEFAULT_ZONE_NAME}"
ZONE_ID="${ZONE_ID:-$DEFAULT_ZONE_ID}"
API_BASE="https://api.cloudflare.com/client/v4"
DRY_RUN=false
BATCH_SIZE=200
usage() {
echo "用法: $0 [--dry-run]"
echo " 方式一:环境变量 CF_API_TOKEN=xxx ZONE_NAME=jackadam.top $0"
echo " 方式二:脚本内配置 在 DEFAULT_* 变量中填写后直接运行"
echo " --dry-run 仅列出待删除记录,不执行删除"
exit 1
}
for arg in "$@"; do
case "$arg" in
--dry-run) DRY_RUN=true ;;
-h|--help) usage ;;
esac
done
if [[ -z "${CF_API_TOKEN}" ]]; then
echo "[ERROR] 请设置 CF_API_TOKEN环境变量或脚本内 DEFAULT_CF_API_TOKEN" >&2
usage
fi
# 若未填 ZONE_ID用 ZONE_NAME 查询
if [[ -n "${ZONE_NAME}" && -z "${ZONE_ID}" ]]; then
echo "[INFO] 查询区域 ${ZONE_NAME} 的 ZONE_ID..."
resp=$(curl -s -X GET "${API_BASE}/zones?name=${ZONE_NAME}" \
-H "Authorization: Bearer ${CF_API_TOKEN}" \
-H "Content-Type: application/json")
if ! echo "$resp" | jq -e '.success == true' >/dev/null 2>&1; then
echo "[ERROR] 查询区域失败: $(echo "$resp" | jq -r '.errors[0].message // .')" >&2
exit 1
fi
ZONE_ID=$(echo "$resp" | jq -r '.result[0].id // empty')
if [[ -z "$ZONE_ID" ]]; then
echo "[ERROR] 未找到区域: ${ZONE_NAME}" >&2
exit 1
fi
echo "[INFO] ZONE_ID=${ZONE_ID}"
fi
if [[ -z "${ZONE_ID}" ]]; then
echo "[ERROR] 请设置 ZONE_NAME 或 ZONE_ID环境变量或脚本内 DEFAULT_ZONE_*" >&2
usage
fi
# 分页获取所有 DNS 记录,筛选 _acme-challenge
echo "[INFO] 获取 DNS 记录列表..."
all_ids=()
page=1
per_page=100
while true; do
resp=$(curl -s -X GET "${API_BASE}/zones/${ZONE_ID}/dns_records?per_page=${per_page}&page=${page}" \
-H "Authorization: Bearer ${CF_API_TOKEN}" \
-H "Content-Type: application/json")
if ! echo "$resp" | jq -e '.success == true' >/dev/null 2>&1; then
echo "[ERROR] 获取记录失败: $(echo "$resp" | jq -r '.errors[0].message // .')" >&2
exit 1
fi
# 筛选 name 包含 _acme-challenge 的记录
ids=$(echo "$resp" | jq -r '.result[] | select(.name | contains("_acme-challenge")) | .id')
names=$(echo "$resp" | jq -r '.result[] | select(.name | contains("_acme-challenge")) | "\(.type) \(.name) -> \(.content)"')
while IFS= read -r id; do
[[ -n "$id" ]] && all_ids+=("$id")
done <<< "$ids"
if [[ -n "$names" ]]; then
echo "$names" | while read -r line; do
[[ -n "$line" ]] && echo " - $line"
done
fi
fetched=$(echo "$resp" | jq -r '.result | length')
[[ "$fetched" -lt "$per_page" ]] && break
((page++)) || true
done
count=${#all_ids[@]}
echo "[INFO] 共找到 ${count} 条 _acme-challenge 相关记录"
if [[ $count -eq 0 ]]; then
echo "[INFO] 无需删除"
exit 0
fi
if [[ "$DRY_RUN" == "true" ]]; then
echo "[DRY-RUN] 未执行删除,以上 ${count} 条记录将在去掉 --dry-run 后被删除"
exit 0
fi
# 分批删除(使用 jq 构建 JSON 避免转义问题)
deleted=0
for ((i=0; i<count; i+=BATCH_SIZE)); do
batch=("${all_ids[@]:i:BATCH_SIZE}")
body=$(printf '%s\n' "${batch[@]}" | jq -R -s 'split("\n") | map(select(length>0)) | {deletes: map({id: .})}')
echo "[INFO] 删除第 $((i/BATCH_SIZE + 1)) 批,共 ${#batch[@]} 条..."
resp=$(curl -s -X POST "${API_BASE}/zones/${ZONE_ID}/dns_records/batch" \
-H "Authorization: Bearer ${CF_API_TOKEN}" \
-H "Content-Type: application/json" \
-d "$body")
if ! echo "$resp" | jq -e '.success == true' >/dev/null 2>&1; then
echo "[ERROR] 批量删除失败: $(echo "$resp" | jq -r '.errors[0].message // .')" >&2
echo "$resp" | jq '.' >&2
exit 1
fi
deleted=$((deleted + ${#batch[@]}))
echo "[OK] 已删除 ${deleted}/${count}"
# 避免 API 限流
[[ $((i + BATCH_SIZE)) -lt $count ]] && sleep 1
done
echo "[DONE] 共删除 ${deleted} 条 _acme-challenge 记录"