update hy2.sh

This commit is contained in:
2026-03-19 15:50:04 +08:00
parent 1a9c6bece4
commit 7cd9d5c415

74
hy2.sh
View File

@@ -1,6 +1,6 @@
#!/usr/bin/env bash #!/usr/bin/env bash
set -Eeuo pipefail set -Eeuo pipefail
trap 'echo "[错误] 第 $LINENO 行执行失败:$BASH_COMMAND"' ERR trap 'echo "[错误] 第 $LINENO 行执行失败:$BASH_COMMAND" >&2' ERR
CONFIG_FILE="/etc/hysteria/config.yaml" CONFIG_FILE="/etc/hysteria/config.yaml"
SERVICE_NAME="hysteria-server.service" SERVICE_NAME="hysteria-server.service"
@@ -41,6 +41,20 @@ prompt_nonempty() {
done 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() { confirm_yn() {
local prompt="${1:-是否继续}" local prompt="${1:-是否继续}"
local answer local answer
@@ -87,6 +101,24 @@ generate_password() {
echo 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() { get_server_ip() {
local ipv4 ipv6 local ipv4 ipv6
ipv4="$(curl -4 -fsSL https://api.ipify.org || true)" ipv4="$(curl -4 -fsSL https://api.ipify.org || true)"
@@ -269,7 +301,10 @@ create_cf_dns_record_type() {
EOF 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() { create_cloudflare_dns_record() {
@@ -284,25 +319,33 @@ create_cloudflare_dns_record() {
echo "Zone: ${zone}" >&2 echo "Zone: ${zone}" >&2
echo "完整域名: ${full_domain}" >&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 if [[ -z "$zone_id" ]]; then
red "无法获取 Cloudflare Zone ID请检查 Token 权限或 Zone 名称。" red "无法获取 Cloudflare Zone ID请检查 Token 权限或 Zone 名称。" >&2
exit 1 return 1
fi fi
delete_existing_cf_dns_record "$zone_id" "$full_domain" "A" || true delete_existing_cf_dns_record "$zone_id" "$full_domain" "A" || true
delete_existing_cf_dns_record "$zone_id" "$full_domain" "AAAA" || true delete_existing_cf_dns_record "$zone_id" "$full_domain" "AAAA" || true
if [[ -n "$ipv4" ]]; then 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 echo "已创建 A 记录 -> ${ipv4}" >&2
fi fi
if [[ -n "$ipv6" ]]; then 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 echo "已创建 AAAA 记录 -> ${ipv6}" >&2
fi fi
if ! validate_domain "$full_domain"; then
red "生成的域名格式无效:${full_domain}" >&2
return 1
fi
printf '%s\n' "$full_domain" printf '%s\n' "$full_domain"
} }
@@ -320,6 +363,14 @@ write_config() {
local cf_token="$3" local cf_token="$3"
local password="$4" local password="$4"
local proxy_url="$5" 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 echo
blue "==> 即将写入如下配置到 ${CONFIG_FILE}" blue "==> 即将写入如下配置到 ${CONFIG_FILE}"
@@ -334,7 +385,7 @@ acme:
dns: dns:
name: cloudflare name: cloudflare
config: config:
cloudflare_api_token: ${cf_token} cloudflare_api_token: ${masked_token}
auth: auth:
type: password type: password
@@ -454,7 +505,7 @@ main() {
subdomain="${subdomain:-$default_subdomain}" subdomain="${subdomain:-$default_subdomain}"
subdomain="$(printf '%s' "$subdomain" | tr 'A-Z' 'a-z' | tr -cd 'a-z0-9-')" 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 export CF_API_TOKEN
password="$(generate_password)" password="$(generate_password)"
@@ -476,7 +527,10 @@ main() {
proxy_url="$(prompt_nonempty '请输入最终用于 masquerade 的完整 URL例如 https://example.com/: ')" proxy_url="$(prompt_nonempty '请输入最终用于 masquerade 的完整 URL例如 https://example.com/: ')"
if confirm_yn "是否在 Cloudflare 中自动创建 DNS 记录 ${subdomain}.${zone}"; then 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 else
domain="$(prompt_nonempty '请输入已存在并已解析到本机的完整域名: ')" domain="$(prompt_nonempty '请输入已存在并已解析到本机的完整域名: ')"
fi fi