From 0df93ed044144bfbfa71561b5b40e05c3cb0838d Mon Sep 17 00:00:00 2001 From: CN-JS-HuiBai Date: Wed, 15 Apr 2026 21:55:45 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BC=98=E5=8C=96=E5=AE=89=E8=A3=85=E8=84=9A?= =?UTF-8?q?=E6=9C=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- install.sh | 204 ++++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 149 insertions(+), 55 deletions(-) diff --git a/install.sh b/install.sh index cb79c4a4..16f2d843 100644 --- a/install.sh +++ b/install.sh @@ -21,8 +21,11 @@ PUBLISHED_SCRIPT_URL="${PUBLISHED_SCRIPT_URL:-https://s3.cloudyun.top/downloads/ V2BX_DETECTED=0 V2BX_CONFIG_PATH="" UNINSTALL_V2BX_DEFAULT="${UNINSTALL_V2BX_DEFAULT:-n}" +SCRIPT_VERSION="${SCRIPT_VERSION:-v1.2.4}" +declare -a V2BX_IMPORTED_NODE_IDS=() echo -e "${GREEN}Welcome to singbox Release Installation Script${NC}" +echo -e "${GREEN}Script version: ${SCRIPT_VERSION}${NC}" echo -e "${YELLOW}Published install script: ${PUBLISHED_SCRIPT_URL}${NC}" if [[ $EUID -ne 0 ]]; then @@ -36,6 +39,17 @@ if [[ "$OS" != "Linux" ]]; then exit 1 fi +if [[ ! -t 0 ]]; then + if [[ -r /dev/tty ]]; then + exec 3/dev/null 2>&1; then local parsed @@ -97,56 +156,76 @@ with open(path, "r", encoding="utf-8") as f: nodes = data.get("Nodes") or [] node = nodes[0] if nodes else {} -for key in ("ApiHost", "ApiKey", "NodeID"): - value = node.get(key, "") - if value is None: - value = "" - print(str(value)) +api_host = node.get("ApiHost", "") if node else "" +api_key = node.get("ApiKey", "") if node else "" +print(f"API_HOST={api_host or ''}") +print(f"API_KEY={api_key or ''}") +for entry in nodes: + node_id = entry.get("NodeID", "") + if node_id is None: + node_id = "" + print(f"NODE_ID={node_id}") PY )" if [[ -n "$parsed" ]]; then - local parsed_api_host parsed_api_key parsed_node_id - parsed_api_host="$(printf '%s\n' "$parsed" | sed -n '1p')" - parsed_api_key="$(printf '%s\n' "$parsed" | sed -n '2p')" - parsed_node_id="$(printf '%s\n' "$parsed" | sed -n '3p')" - - if [[ -z "${PANEL_URL:-}" && -n "$parsed_api_host" ]]; then - PANEL_URL="$parsed_api_host" - fi - if [[ -z "${PANEL_TOKEN:-}" && -n "$parsed_api_key" ]]; then - PANEL_TOKEN="$parsed_api_key" - fi - if [[ -z "${NODE_ID:-}" && -n "$parsed_node_id" ]]; then - NODE_ID="$parsed_node_id" - fi - - echo -e "${YELLOW}Imported defaults from V2bX config: ApiHost=${parsed_api_host:-}, NodeID=${parsed_node_id:-}${NC}" + local parsed_line + while IFS= read -r parsed_line; do + parsed_line="$(sanitize_value "$parsed_line")" + case "$parsed_line" in + API_HOST=*) + if [[ -z "${PANEL_URL:-}" ]]; then + PANEL_URL="$(sanitize_value "${parsed_line#API_HOST=}")" + fi + ;; + API_KEY=*) + if [[ -z "${PANEL_TOKEN:-}" ]]; then + PANEL_TOKEN="$(sanitize_value "${parsed_line#API_KEY=}")" + fi + ;; + NODE_ID=*) + append_unique_node_id "${parsed_line#NODE_ID=}" + ;; + esac + done <<< "$parsed" fi elif command -v jq >/dev/null 2>&1; then local parsed - parsed="$(jq -r '(.Nodes[0].ApiHost // ""), (.Nodes[0].ApiKey // ""), (.Nodes[0].NodeID // "")' "$V2BX_CONFIG_PATH" 2>/dev/null || true)" + parsed="$(jq -r '(.Nodes[0].ApiHost // "" | "API_HOST=" + .), (.Nodes[0].ApiKey // "" | "API_KEY=" + .), (.Nodes[]?.NodeID // "" | tostring | "NODE_ID=" + .)' "$V2BX_CONFIG_PATH" 2>/dev/null || true)" if [[ -n "$parsed" ]]; then - local parsed_api_host parsed_api_key parsed_node_id - parsed_api_host="$(printf '%s\n' "$parsed" | sed -n '1p')" - parsed_api_key="$(printf '%s\n' "$parsed" | sed -n '2p')" - parsed_node_id="$(printf '%s\n' "$parsed" | sed -n '3p')" - - if [[ -z "${PANEL_URL:-}" && -n "$parsed_api_host" ]]; then - PANEL_URL="$parsed_api_host" - fi - if [[ -z "${PANEL_TOKEN:-}" && -n "$parsed_api_key" ]]; then - PANEL_TOKEN="$parsed_api_key" - fi - if [[ -z "${NODE_ID:-}" && -n "$parsed_node_id" ]]; then - NODE_ID="$parsed_node_id" - fi - - echo -e "${YELLOW}Imported defaults from V2bX config: ApiHost=${parsed_api_host:-}, NodeID=${parsed_node_id:-}${NC}" + local parsed_line + while IFS= read -r parsed_line; do + parsed_line="$(sanitize_value "$parsed_line")" + case "$parsed_line" in + API_HOST=*) + if [[ -z "${PANEL_URL:-}" ]]; then + PANEL_URL="$(sanitize_value "${parsed_line#API_HOST=}")" + fi + ;; + API_KEY=*) + if [[ -z "${PANEL_TOKEN:-}" ]]; then + PANEL_TOKEN="$(sanitize_value "${parsed_line#API_KEY=}")" + fi + ;; + NODE_ID=*) + append_unique_node_id "${parsed_line#NODE_ID=}" + ;; + esac + done <<< "$parsed" fi else echo -e "${YELLOW}Neither python3 nor jq found, skipping automatic V2bX config import.${NC}" fi + if [[ -z "${NODE_ID:-}" && "${#V2BX_IMPORTED_NODE_IDS[@]}" -gt 0 ]]; then + NODE_ID="${V2BX_IMPORTED_NODE_IDS[0]}" + fi + + if [[ "${#V2BX_IMPORTED_NODE_IDS[@]}" -gt 0 ]]; then + echo -e "${YELLOW}Imported defaults from V2bX config: ApiHost=${PANEL_URL:-}, NodeIDs=$(IFS=,; echo "${V2BX_IMPORTED_NODE_IDS[*]}")${NC}" + else + echo -e "${YELLOW}Imported defaults from V2bX config: ApiHost=${PANEL_URL:-}, NodeIDs=${NC}" + fi + return 0 } @@ -172,7 +251,7 @@ prompt_uninstall_v2bx() { return 0 fi - read -p "Detected V2bX. Uninstall it now? [${UNINSTALL_V2BX_DEFAULT}]: " INPUT_UNINSTALL_V2BX + read -u 3 -p "Detected V2bX. Uninstall it now? [${UNINSTALL_V2BX_DEFAULT}]: " INPUT_UNINSTALL_V2BX local uninstall_v2bx_answer uninstall_v2bx_answer=${INPUT_UNINSTALL_V2BX:-$UNINSTALL_V2BX_DEFAULT} @@ -252,32 +331,39 @@ fi load_v2bx_defaults || true +PANEL_URL="$(sanitize_value "${PANEL_URL:-}")" +PANEL_TOKEN="$(sanitize_value "${PANEL_TOKEN:-}")" +NODE_ID="$(sanitize_value "${NODE_ID:-}")" +ENABLE_PROXY_PROTOCOL_HINT="$(sanitize_value "${ENABLE_PROXY_PROTOCOL_HINT:-n}")" + download_binary cleanup_legacy_service -read -p "Enter Panel URL [${PANEL_URL}]: " INPUT_URL -PANEL_URL=${INPUT_URL:-$PANEL_URL} +read -u 3 -p "Enter Panel URL [${PANEL_URL}]: " INPUT_URL +PANEL_URL="$(sanitize_value "${INPUT_URL:-$PANEL_URL}")" -read -p "Enter Panel Token (Node Key) [${PANEL_TOKEN}]: " INPUT_TOKEN -PANEL_TOKEN=${INPUT_TOKEN:-$PANEL_TOKEN} +read -u 3 -p "Enter Panel Token (Node Key) [${PANEL_TOKEN}]: " INPUT_TOKEN +PANEL_TOKEN="$(sanitize_value "${INPUT_TOKEN:-$PANEL_TOKEN}")" -read -p "This node is behind an L4 proxy/LB that sends PROXY protocol? [${ENABLE_PROXY_PROTOCOL_HINT:-n}]: " INPUT_PROXY_PROTOCOL -ENABLE_PROXY_PROTOCOL_HINT=${INPUT_PROXY_PROTOCOL:-${ENABLE_PROXY_PROTOCOL_HINT:-n}} +read -u 3 -p "This node is behind an L4 proxy/LB that sends PROXY protocol? [${ENABLE_PROXY_PROTOCOL_HINT:-n}]: " INPUT_PROXY_PROTOCOL +ENABLE_PROXY_PROTOCOL_HINT="$(sanitize_value "${INPUT_PROXY_PROTOCOL:-${ENABLE_PROXY_PROTOCOL_HINT:-n}}")" declare -a NODE_IDS i=1 while true; do DEFAULT_NODE_ID="" - if [[ "$i" -eq 1 && -n "${NODE_ID:-}" ]]; then + if [[ "$i" -le "${#V2BX_IMPORTED_NODE_IDS[@]}" ]]; then + DEFAULT_NODE_ID="${V2BX_IMPORTED_NODE_IDS[$((i-1))]}" + elif [[ "$i" -eq 1 && -n "${NODE_ID:-}" ]]; then DEFAULT_NODE_ID="$NODE_ID" fi if [[ -n "$DEFAULT_NODE_ID" ]]; then - read -p "Enter Node ID for node #$i [${DEFAULT_NODE_ID}] (type NO to finish): " INPUT_ID + read -u 3 -p "Enter Node ID for node #$i [${DEFAULT_NODE_ID}] (type NO to finish): " INPUT_ID else - read -p "Enter Node ID for node #$i (type NO to finish): " INPUT_ID + read -u 3 -p "Enter Node ID for node #$i (type NO to finish): " INPUT_ID fi - CURRENT_NODE_ID=${INPUT_ID:-$DEFAULT_NODE_ID} + CURRENT_NODE_ID="$(sanitize_value "${INPUT_ID:-$DEFAULT_NODE_ID}")" if [[ "$CURRENT_NODE_ID" =~ ^([nN][oO])$ ]]; then if [[ "${#NODE_IDS[@]}" -eq 0 ]]; then echo -e "${RED}At least one Node ID is required${NC}" @@ -285,31 +371,39 @@ while true; do fi break fi + CURRENT_NODE_ID="$(normalize_node_id_input "$CURRENT_NODE_ID")" if [[ -z "$CURRENT_NODE_ID" ]]; then echo -e "${RED}Node ID is required for node #$i${NC}" exit 1 fi - if ! [[ "$CURRENT_NODE_ID" =~ ^[0-9]+$ ]]; then - echo -e "${RED}Node ID must be a positive integer${NC}" + read -r -a CURRENT_NODE_ID_PARTS <<< "$CURRENT_NODE_ID" + if [[ "${#CURRENT_NODE_ID_PARTS[@]}" -eq 0 ]]; then + echo -e "${RED}Node ID is required for node #$i${NC}" exit 1 fi - NODE_IDS+=("$CURRENT_NODE_ID") + for CURRENT_NODE_ID_PART in "${CURRENT_NODE_ID_PARTS[@]}"; do + if ! [[ "$CURRENT_NODE_ID_PART" =~ ^[0-9]+$ ]]; then + echo -e "${RED}Node ID must be a positive integer, got: ${CURRENT_NODE_ID_PART}${NC}" + exit 1 + fi + NODE_IDS+=("$CURRENT_NODE_ID_PART") + done ((i++)) done NODE_COUNT=${#NODE_IDS[@]} DNS_MODE_DEFAULT=${DNS_MODE:-udp} -read -p "Enter DNS mode [${DNS_MODE_DEFAULT}] (udp/local): " INPUT_DNS_MODE +read -u 3 -p "Enter DNS mode [${DNS_MODE_DEFAULT}] (udp/local): " INPUT_DNS_MODE DNS_MODE=$(echo "${INPUT_DNS_MODE:-$DNS_MODE_DEFAULT}" | tr '[:upper:]' '[:lower:]') case "$DNS_MODE" in udp) DNS_SERVER_DEFAULT=${DNS_SERVER:-1.1.1.1} DNS_SERVER_PORT_DEFAULT=${DNS_SERVER_PORT:-53} - read -p "Enter DNS server [${DNS_SERVER_DEFAULT}]: " INPUT_DNS_SERVER + read -u 3 -p "Enter DNS server [${DNS_SERVER_DEFAULT}]: " INPUT_DNS_SERVER DNS_SERVER=${INPUT_DNS_SERVER:-$DNS_SERVER_DEFAULT} - read -p "Enter DNS server port [${DNS_SERVER_PORT_DEFAULT}]: " INPUT_DNS_SERVER_PORT + read -u 3 -p "Enter DNS server port [${DNS_SERVER_PORT_DEFAULT}]: " INPUT_DNS_SERVER_PORT DNS_SERVER_PORT=${INPUT_DNS_SERVER_PORT:-$DNS_SERVER_PORT_DEFAULT} if [[ -z "$DNS_SERVER" ]]; then echo -e "${RED}DNS server is required in udp mode${NC}"