From 7cd9d5c4159ad355a3322f1539002d37f49ea294 Mon Sep 17 00:00:00 2001 From: svefnz Date: Thu, 19 Mar 2026 15:50:04 +0800 Subject: [PATCH] update hy2.sh --- hy2.sh | 76 +++++++++++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 65 insertions(+), 11 deletions(-) diff --git a/hy2.sh b/hy2.sh index 1bb2bb8..dc32ec3 100644 --- a/hy2.sh +++ b/hy2.sh @@ -1,6 +1,6 @@ #!/usr/bin/env bash set -Eeuo pipefail -trap 'echo "[错误] 第 $LINENO 行执行失败:$BASH_COMMAND"' ERR +trap 'echo "[错误] 第 $LINENO 行执行失败:$BASH_COMMAND" >&2' ERR CONFIG_FILE="/etc/hysteria/config.yaml" SERVICE_NAME="hysteria-server.service" @@ -41,6 +41,20 @@ prompt_nonempty() { done } +prompt_secret_nonempty() { + local prompt="$1" + local value="" + while true; do + read -r -s -p "$prompt" value + echo + if [[ -n "${value// }" ]]; then + printf '%s' "$value" + return 0 + fi + yellow "输入不能为空,请重新输入。" + done +} + confirm_yn() { local prompt="${1:-是否继续?}" local answer @@ -87,6 +101,24 @@ generate_password() { echo } +mask_secret() { + local secret="$1" + local len="${#secret}" + if (( len <= 8 )); then + printf '********' + else + printf '%s****%s' "${secret:0:4}" "${secret: -4}" + fi +} + +validate_domain() { + local domain="$1" + [[ -n "$domain" ]] || return 1 + [[ "$domain" != *$'\n'* ]] || return 1 + [[ "$domain" != *$'\r'* ]] || return 1 + [[ "$domain" =~ ^([a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?\.)+[a-z]{2,63}$ ]] +} + get_server_ip() { local ipv4 ipv6 ipv4="$(curl -4 -fsSL https://api.ipify.org || true)" @@ -269,7 +301,10 @@ create_cf_dns_record_type() { EOF ) - cf_api_request POST "https://api.cloudflare.com/client/v4/zones/${zone_id}/dns_records" "$payload" >/dev/null + if ! cf_api_request POST "https://api.cloudflare.com/client/v4/zones/${zone_id}/dns_records" "$payload" >/dev/null; then + red "创建 Cloudflare ${type} 记录失败,请检查 Token 权限和 Zone 配置。" >&2 + return 1 + fi } create_cloudflare_dns_record() { @@ -284,25 +319,33 @@ create_cloudflare_dns_record() { echo "Zone: ${zone}" >&2 echo "完整域名: ${full_domain}" >&2 - zone_id="$(get_cf_zone_id "$zone")" + if ! zone_id="$(get_cf_zone_id "$zone")"; then + red "调用 Cloudflare API 获取 Zone ID 失败,请检查网络和 Token 权限。" >&2 + return 1 + fi if [[ -z "$zone_id" ]]; then - red "无法获取 Cloudflare Zone ID,请检查 Token 权限或 Zone 名称。" - exit 1 + red "无法获取 Cloudflare Zone ID,请检查 Token 权限或 Zone 名称。" >&2 + return 1 fi delete_existing_cf_dns_record "$zone_id" "$full_domain" "A" || true delete_existing_cf_dns_record "$zone_id" "$full_domain" "AAAA" || true if [[ -n "$ipv4" ]]; then - create_cf_dns_record_type "$zone_id" "$full_domain" "A" "$ipv4" + create_cf_dns_record_type "$zone_id" "$full_domain" "A" "$ipv4" || return 1 echo "已创建 A 记录 -> ${ipv4}" >&2 fi if [[ -n "$ipv6" ]]; then - create_cf_dns_record_type "$zone_id" "$full_domain" "AAAA" "$ipv6" + create_cf_dns_record_type "$zone_id" "$full_domain" "AAAA" "$ipv6" || return 1 echo "已创建 AAAA 记录 -> ${ipv6}" >&2 fi + if ! validate_domain "$full_domain"; then + red "生成的域名格式无效:${full_domain}" >&2 + return 1 + fi + printf '%s\n' "$full_domain" } @@ -320,6 +363,14 @@ write_config() { local cf_token="$3" local password="$4" local proxy_url="$5" + local masked_token + + if ! validate_domain "$domain"; then + red "域名无效,拒绝写入配置:${domain@Q}" + exit 1 + fi + + masked_token="$(mask_secret "$cf_token")" echo blue "==> 即将写入如下配置到 ${CONFIG_FILE}" @@ -334,7 +385,7 @@ acme: dns: name: cloudflare config: - cloudflare_api_token: ${cf_token} + cloudflare_api_token: ${masked_token} auth: type: password @@ -454,7 +505,7 @@ main() { subdomain="${subdomain:-$default_subdomain}" subdomain="$(printf '%s' "$subdomain" | tr 'A-Z' 'a-z' | tr -cd 'a-z0-9-')" - CF_API_TOKEN="$(prompt_nonempty '请输入 Cloudflare API Token: ')" + CF_API_TOKEN="$(prompt_secret_nonempty '请输入 Cloudflare API Token: ')" export CF_API_TOKEN password="$(generate_password)" @@ -476,7 +527,10 @@ main() { proxy_url="$(prompt_nonempty '请输入最终用于 masquerade 的完整 URL(例如 https://example.com/): ')" if confirm_yn "是否在 Cloudflare 中自动创建 DNS 记录 ${subdomain}.${zone}?"; then - domain="$(create_cloudflare_dns_record "$zone" "$subdomain" "$ipv4" "$ipv6")" + if ! domain="$(create_cloudflare_dns_record "$zone" "$subdomain" "$ipv4" "$ipv6")"; then + red "自动创建 Cloudflare DNS 记录失败,脚本已中止,未写入 Hysteria 配置。" + exit 1 + fi else domain="$(prompt_nonempty '请输入已存在并已解析到本机的完整域名: ')" fi @@ -486,4 +540,4 @@ main() { show_result "${domain}" "${password}" "${proxy_url}" "${ip_info}" } -main "$@" \ No newline at end of file +main "$@"