#!/bin/bash # Ensure necessary packages are installed if ! command -v jq &> /dev/null || ! command -v qrencode &> /dev/null || ! command -v curl &> /dev/null; then echo "Necessary packages are not installed. Please wait while they are being installed..." apt-get update -qq && apt-get install jq qrencode curl -y >/dev/null 2>&1 fi # Function to install and configure Hysteria2 install_and_configure() { if systemctl is-active --quiet hysteria-server.service; then echo -e "\033[0;31mError:\033[0mHysteria2 is already installed and running." echo echo "If you need to update the core, please use the 'Update Core' option." else echo "Installing and configuring Hysteria2..." bash <(curl -s https://raw.githubusercontent.com/H-Return/Hysteria2/main/install.sh) echo -e "\n\n\n" echo "Installation and configuration complete." fi } # Function to update Hysteria2 update_core() { echo "Starting the update process for Hysteria2..." echo "Backing up the current configuration..." cp /etc/hysteria/config.json /etc/hysteria/config_backup.json if [ $? -ne 0 ]; then echo "Error: Failed to back up configuration. Aborting update." return 1 fi echo "Downloading and installing the latest version of Hysteria2..." bash <(curl -fsSL https://get.hy2.sh/) >/dev/null 2>&1 if [ $? -ne 0 ]; then echo "Error: Failed to download or install the latest version. Restoring backup configuration." mv /etc/hysteria/config_backup.json /etc/hysteria/config.json systemctl restart hysteria-server.service >/dev/null 2>&1 return 1 fi echo "Restoring configuration from backup..." mv /etc/hysteria/config_backup.json /etc/hysteria/config.json if [ $? -ne 0 ]; then echo "Error: Failed to restore configuration from backup." return 1 fi echo "Modifying systemd service to use config.json..." sed -i 's|/etc/hysteria/config.yaml|/etc/hysteria/config.json|' /etc/systemd/system/hysteria-server.service if [ $? -ne 0 ]; then echo "Error: Failed to modify systemd service." return 1 fi rm /etc/hysteria/config.yaml systemctl daemon-reload >/dev/null 2>&1 systemctl restart hysteria-server.service >/dev/null 2>&1 if [ $? -ne 0 ]; then echo "Error: Failed to restart Hysteria2 service." return 1 fi echo "Hysteria2 has been successfully updated." echo "" return 0 } # Function to change port change_port() { while true; do read -p "Enter the new port number you want to use: " port if ! [[ "$port" =~ ^[0-9]+$ ]] || [ "$port" -lt 1 ] || [ "$port" -gt 65535 ]; then echo "Invalid port number. Please enter a number between 1 and 65535." else break fi done if [ -f "/etc/hysteria/config.json" ]; then jq --arg port "$port" '.listen = ":" + $port' /etc/hysteria/config.json > /etc/hysteria/config_temp.json && mv /etc/hysteria/config_temp.json /etc/hysteria/config.json systemctl restart hysteria-server.service >/dev/null 2>&1 echo "Port changed successfully to $port." else echo "Error: Config file /etc/hysteria/config.json not found." fi } # Function to show URI if Hysteria2 is installed and active show_uri() { if [ -f "/etc/hysteria/config.json" ]; then if systemctl is-active --quiet hysteria-server.service; then # Get the list of configured usernames usernames=$(jq -r '.auth.userpass | keys_unsorted[]' /etc/hysteria/config.json) # Prompt the user to select a username PS3="Select a username: " select username in $usernames; do if [ -n "$username" ]; then # Get the selected user's password and other required parameters authpassword=$(jq -r ".auth.userpass[\"$username\"]" /etc/hysteria/config.json) port=$(jq -r '.listen' /etc/hysteria/config.json | cut -d':' -f2) sha256=$(jq -r '.tls.pinSHA256' /etc/hysteria/config.json) obfspassword=$(jq -r '.obfs.salamander.password' /etc/hysteria/config.json) # Get IP addresses IP=$(curl -s -4 ip.sb) IP6=$(curl -s -6 ip.sb) # Construct URI URI="hy2://$username:$authpassword@$IP:$port?obfs=salamander&obfs-password=$obfspassword&pinSHA256=$sha256&insecure=1&sni=bts.com#$username-IPv4" URI6="hy2://$username:$authpassword@[$IP6]:$port?obfs=salamander&obfs-password=$obfspassword&pinSHA256=$sha256&insecure=1&sni=bts.com#$username-IPv6" cols=$(tput cols) rows=$(tput lines) qr1=$(echo -n "$URI" | qrencode -t UTF8 -s 3 -m 2) qr2=$(echo -n "$URI6" | qrencode -t UTF8 -s 3 -m 2) echo -e "\nIPv4:\n" echo "$qr1" | while IFS= read -r line; do printf "%*s\n" $(( (${#line} + cols) / 2)) "$line" done echo -e "\nIPv6:\n" echo "$qr2" | while IFS= read -r line; do printf "%*s\n" $(( (${#line} + cols) / 2)) "$line" done echo echo "IPv4: $URI" echo echo "IPv6: $URI6" echo break else echo "Invalid selection. Please try again." fi done else echo "Error: Hysteria2 is not active." fi else echo "Error: Config file /etc/hysteria/config.json not found." fi } # Function to check traffic status for each user traffic_status() { green='\033[0;32m' cyan='\033[0;36m' NC='\033[0m' secret=$(jq -r '.trafficStats.secret' /etc/hysteria/config.json) if [ -z "$secret" ]; then echo "Error: Secret not found in config.json" return fi response=$(curl -s -H "Authorization: $secret" http://127.0.0.1:25413/traffic) if [ -z "$response" ] || [ "$response" = "{}" ]; then echo -e "No traffic data available." return fi # Get online status online_response=$(curl -s -H "Authorization: $secret" http://127.0.0.1:25413/online) if [ -z "$online_response" ]; then echo -e "No online data available." return fi echo "Traffic status for each user:" echo "-------------------------------------------------" printf "%-15s %-15s %-15s %-10s\n" "User" "Upload (TX)" "Download (RX)" "Status" echo "-------------------------------------------------" users=$(echo "$response" | jq -r 'keys[]') for user in $users; do tx_bytes=$(echo "$response" | jq -r ".[\"$user\"].tx // 0") rx_bytes=$(echo "$response" | jq -r ".[\"$user\"].rx // 0") online=$(echo "$online_response" | jq -r ".[\"$user\"] // 0") formatted_tx=$(format_bytes "$tx_bytes") formatted_rx=$(format_bytes "$rx_bytes") status="" if [ "$online" -eq 1 ]; then status="Online" else status="Offline" fi # Print user traffic information with color formatting printf "%-15s ${green}%-15s${NC} ${cyan}%-15s${NC} %-10s\n" "$user" "$formatted_tx" "$formatted_rx" "$status" echo "-------------------------------------------------" done } # Helper function to format bytes into human-readable format format_bytes() { bytes=$1 if [ "$bytes" -lt 1024 ]; then echo "${bytes}B" elif [ "$bytes" -lt 1048576 ]; then echo "$(bc <<< "scale=2; $bytes / 1024")KB" elif [ "$bytes" -lt 1073741824 ]; then echo "$(bc <<< "scale=2; $bytes / 1048576")MB" elif [ "$bytes" -lt 1099511627776 ]; then echo "$(bc <<< "scale=2; $bytes / 1073741824")GB" else echo "$(bc <<< "scale=2; $bytes / 1099511627776")TB" fi } # Function to uninstall Hysteria2 uninstall_hysteria() { echo "Uninstalling Hysteria2..." sleep 1 echo "Running uninstallation script..." bash <(curl -fsSL https://get.hy2.sh/) --remove >/dev/null 2>&1 sleep 1 echo "Removing Hysteria folder..." rm -rf /etc/hysteria >/dev/null 2>&1 sleep 1 echo "Deleting hysteria user..." userdel -r hysteria >/dev/null 2>&1 sleep 1 echo "Removing systemd service files..." rm -f /etc/systemd/system/multi-user.target.wants/hysteria-server.service >/dev/null 2>&1 rm -f /etc/systemd/system/multi-user.target.wants/hysteria-server@*.service >/dev/null 2>&1 sleep 1 echo "Reloading systemd daemon..." systemctl daemon-reload >/dev/null 2>&1 sleep 1 echo "Hysteria2 uninstalled!" echo "" } # Function to install TCP Brutal install_tcp_brutal() { echo "Installing TCP Brutal..." bash <(curl -fsSL https://tcp.hy2.sh/) sleep 3 clear echo "TCP Brutal installation complete." } # Function to install WARP and update config.json install_warp() { echo "Installing WARP..." bash <(curl -fsSL git.io/warp.sh) wgx if [ -f "/etc/hysteria/config.json" ]; then jq '.outbounds += [{"name": "warps", "type": "direct", "direct": {"mode": 4, "bindDevice": "wgcf"}}]' /etc/hysteria/config.json > /etc/hysteria/config_temp.json && mv /etc/hysteria/config_temp.json /etc/hysteria/config.json systemctl restart hysteria-server.service >/dev/null 2>&1 echo "WARP installed and outbound added to config.json." else echo "Error: Config file /etc/hysteria/config.json not found." fi } # Function to configure WARP configure_warp() { if [ -f "/etc/hysteria/config.json" ]; then # Check the current status of WARP configurations warp_all_status=$(jq -r 'if .acl.inline | index("warps(all)") then "WARP active" else "Direct" end' /etc/hysteria/config.json) google_openai_status=$(jq -r 'if (.acl.inline | index("warps(geoip:google)")) or (.acl.inline | index("warps(geosite:google)")) or (.acl.inline | index("warps(geosite:netflix)")) or (.acl.inline | index("warps(geosite:spotify)")) or (.acl.inline | index("warps(geosite:openai)")) or (.acl.inline | index("warps(geoip:openai)")) then "WARP active" else "Direct" end' /etc/hysteria/config.json) iran_status=$(jq -r 'if (.acl.inline | index("warps(geosite:ir)")) and (.acl.inline | index("warps(geoip:ir)")) then "Use WARP" else "Reject" end' /etc/hysteria/config.json) echo "===== WARP Configuration Menu =====" echo "1. Use WARP for all traffic ($warp_all_status)" echo "2. Use WARP for Google, OpenAI, etc. ($google_openai_status)" echo "3. Use WARP for geosite:ir and geoip:ir ($iran_status)" echo "4. Back to Advance Menu" echo "===================================" read -p "Enter your choice: " choice case $choice in 1) if [ "$warp_all_status" == "WARP active" ]; then jq 'del(.acl.inline[] | select(. == "warps(all)"))' /etc/hysteria/config.json > /etc/hysteria/config_temp.json && mv /etc/hysteria/config_temp.json /etc/hysteria/config.json echo "Traffic configuration changed to Direct." else jq '.acl.inline += ["warps(all)"]' /etc/hysteria/config.json > /etc/hysteria/config_temp.json && mv /etc/hysteria/config_temp.json /etc/hysteria/config.json echo "Traffic configuration changed to WARP." fi ;; 2) if [ "$google_openai_status" == "WARP active" ]; then jq 'del(.acl.inline[] | select(. == "warps(geoip:google)" or . == "warps(geosite:google)" or . == "warps(geosite:netflix)" or . == "warps(geosite:spotify)" or . == "warps(geosite:openai)" or . == "warps(geoip:openai)"))' /etc/hysteria/config.json > /etc/hysteria/config_temp.json && mv /etc/hysteria/config_temp.json /etc/hysteria/config.json echo "WARP configuration for Google, OpenAI, etc. removed." else jq '.acl.inline += ["warps(geoip:google)", "warps(geosite:google)", "warps(geosite:netflix)", "warps(geosite:spotify)", "warps(geosite:openai)", "warps(geoip:openai)"]' /etc/hysteria/config.json > /etc/hysteria/config_temp.json && mv /etc/hysteria/config_temp.json /etc/hysteria/config.json echo "WARP configured for Google, OpenAI, etc." fi ;; 3) if [ "$iran_status" == "Use WARP" ]; then jq '(.acl.inline[] | select(. == "warps(geosite:ir)")) = "reject(geosite:ir)" | (.acl.inline[] | select(. == "warps(geoip:ir)")) = "reject(geoip:ir)"' /etc/hysteria/config.json > /etc/hysteria/config_temp.json && mv /etc/hysteria/config_temp.json /etc/hysteria/config.json echo "Configuration changed to Reject for geosite:ir and geoip:ir." else jq '(.acl.inline[] | select(. == "reject(geosite:ir)")) = "warps(geosite:ir)" | (.acl.inline[] | select(. == "reject(geoip:ir)")) = "warps(geoip:ir)"' /etc/hysteria/config.json > /etc/hysteria/config_temp.json && mv /etc/hysteria/config_temp.json /etc/hysteria/config.json echo "Configuration changed to Use WARP for geosite:ir and geoip:ir." fi ;; 4) return ;; *) echo "Invalid option. Please try again." ;; esac systemctl restart hysteria-server.service >/dev/null 2>&1 else echo "Error: Config file /etc/hysteria/config.json not found." fi } # Function to add a new user to the configuration add_user() { if [ -f "/etc/hysteria/config.json" ]; then while true; do read -p "Enter the username: " username # Validate username (only lowercase letters and numbers allowed) if [[ "$username" =~ ^[a-z0-9]+$ ]]; then break else echo -e "\033[0;31mError:\033[0m Username can only contain lowercase letters and numbers." fi done password=$(curl -s "https://api.genratr.com/?length=32&uppercase&lowercase&numbers" | jq -r '.password') jq --arg username "$username" --arg password "$password" '.auth.userpass[$username] = $password' /etc/hysteria/config.json > /etc/hysteria/config_temp.json && mv /etc/hysteria/config_temp.json /etc/hysteria/config.json systemctl restart hysteria-server.service >/dev/null 2>&1 echo -e "\033[0;32mUser $username added successfully.\033[0m" else echo -e "\033[0;31mError:\033[0m Config file /etc/hysteria/config.json not found." fi } # Function to remove a user from the configuration remove_user() { if [ -f "/etc/hysteria/config.json" ]; then # Extract current users from the config file users=$(jq -r '.auth.userpass | keys | .[]' /etc/hysteria/config.json) if [ -z "$users" ]; then echo "No users found." return fi # Display current users with numbering echo "Current users:" echo "-----------------" i=1 for user in $users; do echo "$i. $user" ((i++)) done echo "-----------------" read -p "Enter the number of the user to remove: " selected_number if ! [[ "$selected_number" =~ ^[0-9]+$ ]]; then echo "Error: Invalid input. Please enter a number." return fi if [ "$selected_number" -lt 1 ] || [ "$selected_number" -gt "$i" ]; then echo "Error: Invalid selection. Please enter a number within the range." return fi selected_user=$(echo "$users" | sed -n "${selected_number}p") jq --arg selected_user "$selected_user" 'del(.auth.userpass[$selected_user])' /etc/hysteria/config.json > /etc/hysteria/config_temp.json && mv /etc/hysteria/config_temp.json /etc/hysteria/config.json systemctl restart hysteria-server.service >/dev/null 2>&1 echo "User $selected_user removed successfully." else echo "Error: Config file /etc/hysteria/config.json not found." fi }