Files
Blitz-Proxy/menu.sh
2025-06-08 20:09:47 +03:30

1194 lines
48 KiB
Bash

#!/bin/bash
source /etc/hysteria/core/scripts/utils.sh
source /etc/hysteria/core/scripts/path.sh
source /etc/hysteria/core/scripts/services_status.sh >/dev/null 2>&1
check_services() {
for service in "${services[@]}"; do
service_base_name=$(basename "$service" .service)
display_name=$(echo "$service_base_name" | sed -E 's/([^-]+)-?/\u\1/g')
if systemctl is-active --quiet "$service"; then
echo -e "${NC}${display_name}:${green} Active${NC}"
else
echo -e "${NC}${display_name}:${red} Inactive${NC}"
fi
done
}
# OPTION HANDLERS (ONLY NEEDED ONE)
hysteria2_install_handler() {
if systemctl is-active --quiet hysteria-server.service; then
echo "The hysteria-server.service is currently active."
echo "If you need to update the core, please use the 'Update Core' option."
return
fi
while true; do
read -p "Enter the SNI (default: bts.com): " sni
sni=${sni:-bts.com}
read -p "Enter the 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
python3 $CLI_PATH install-hysteria2 --port "$port" --sni "$sni"
cat <<EOF > /etc/hysteria/.configs.env
SNI=$sni
EOF
python3 $CLI_PATH ip-address
}
hysteria2_add_user_handler() {
while true; do
read -p "Enter the username: " username
if [[ "$username" =~ ^[a-zA-Z0-9]+$ ]]; then
if [[ -n $(python3 $CLI_PATH get-user -u "$username") ]]; then
echo -e "${red}Error:${NC} Username already exists. Please choose another username."
else
break
fi
else
echo -e "${red}Error:${NC} Username can only contain letters and numbers."
fi
done
read -p "Enter the traffic limit (in GB): " traffic_limit_GB
read -p "Enter the expiration days: " expiration_days
password=$(pwgen -s 32 1)
creation_date=$(date +%Y-%m-%d)
python3 $CLI_PATH add-user --username "$username" --traffic-limit "$traffic_limit_GB" --expiration-days "$expiration_days" --password "$password" --creation-date "$creation_date"
}
hysteria2_edit_user_handler() {
# Function to prompt for user input with validation
prompt_for_input() {
local prompt_message="$1"
local validation_regex="$2"
local default_value="$3"
local input_variable_name="$4"
while true; do
read -p "$prompt_message" input
if [[ -z "$input" ]]; then
input="$default_value"
fi
if [[ "$input" =~ $validation_regex ]]; then
eval "$input_variable_name='$input'"
break
else
echo -e "${red}Error:${NC} Invalid input. Please try again."
fi
done
}
# Prompt for username
prompt_for_input "Enter the username you want to edit: " '^[a-zA-Z0-9]+$' '' username
# Check if user exists
user_exists_output=$(python3 $CLI_PATH get-user -u "$username" 2>&1)
if [[ -z "$user_exists_output" ]]; then
echo -e "${red}Error:${NC} User '$username' not found or an error occurred."
return 1
fi
# Prompt for new username
prompt_for_input "Enter the new username (leave empty to keep the current username): " '^[a-zA-Z0-9]*$' '' new_username
# Prompt for new traffic limit
prompt_for_input "Enter the new traffic limit (in GB) (leave empty to keep the current limit): " '^[0-9]*$' '' new_traffic_limit_GB
# Prompt for new expiration days
prompt_for_input "Enter the new expiration days (leave empty to keep the current expiration days): " '^[0-9]*$' '' new_expiration_days
# Determine if we need to renew password
while true; do
read -p "Do you want to generate a new password? (y/n): " renew_password
case "$renew_password" in
y|Y) renew_password=true; break ;;
n|N) renew_password=false; break ;;
*) echo -e "${red}Error:${NC} Please answer 'y' or 'n'." ;;
esac
done
# Determine if we need to renew creation date
while true; do
read -p "Do you want to generate a new creation date? (y/n): " renew_creation_date
case "$renew_creation_date" in
y|Y) renew_creation_date=true; break ;;
n|N) renew_creation_date=false; break ;;
*) echo -e "${red}Error:${NC} Please answer 'y' or 'n'." ;;
esac
done
# Determine if user should be blocked
while true; do
read -p "Do you want to block the user? (y/n): " block_user
case "$block_user" in
y|Y) blocked=true; break ;;
n|N) blocked=false; break ;;
*) echo -e "${red}Error:${NC} Please answer 'y' or 'n'." ;;
esac
done
# Construct the arguments for the edit-user command
args=()
if [[ -n "$new_username" ]]; then args+=("--new-username" "$new_username"); fi
if [[ -n "$new_traffic_limit_GB" ]]; then args+=("--new-traffic-limit" "$new_traffic_limit_GB"); fi
if [[ -n "$new_expiration_days" ]]; then args+=("--new-expiration-days" "$new_expiration_days"); fi
if [[ "$renew_password" == "true" ]]; then args+=("--renew-password"); fi
if [[ "$renew_creation_date" == "true" ]]; then args+=("--renew-creation-date"); fi
if [[ "$blocked" == "true" ]]; then args+=("--blocked"); fi
# Call the edit-user script with the constructed arguments
python3 $CLI_PATH edit-user --username "$username" "${args[@]}"
}
hysteria2_remove_user_handler() {
while true; do
read -p "Enter the username: " username
if [[ "$username" =~ ^[a-zA-Z0-9]+$ ]]; then
break
else
echo -e "${red}Error:${NC} Username can only contain letters and numbers."
fi
done
python3 $CLI_PATH remove-user --username "$username"
}
hysteria2_get_user_handler() {
while true; do
read -p "Enter the username: " username
if [[ "$username" =~ ^[a-zA-Z0-9]+$ ]]; then
break
else
echo -e "${red}Error:${NC} Username can only contain letters and numbers."
fi
done
user_data=$(python3 "$CLI_PATH" get-user --username "$username" 2>/dev/null)
if [[ $exit_code -ne 0 || -z "$user_data" ]]; then
echo -e "${red}Error:${NC} User '$username' not found or invalid response."
return 1
fi
password=$(echo "$user_data" | jq -r '.password // "N/A"')
max_download_bytes=$(echo "$user_data" | jq -r '.max_download_bytes // 0')
upload_bytes=$(echo "$user_data" | jq -r '.upload_bytes // 0')
download_bytes=$(echo "$user_data" | jq -r '.download_bytes // 0')
account_creation_date=$(echo "$user_data" | jq -r '.account_creation_date // "N/A"')
expiration_days=$(echo "$user_data" | jq -r '.expiration_days // 0')
blocked=$(echo "$user_data" | jq -r '.blocked // false')
status=$(echo "$user_data" | jq -r '.status // "N/A"')
total_usage=$((upload_bytes + download_bytes))
max_download_gb=$(echo "scale=2; $max_download_bytes / 1073741824" | bc)
upload_gb=$(echo "scale=2; $upload_bytes / 1073741824" | bc)
download_gb=$(echo "scale=2; $download_bytes / 1073741824" | bc)
total_usage_gb=$(echo "scale=2; $total_usage / 1073741824" | bc)
expiration_date=$(date -d "$account_creation_date + $expiration_days days" +"%Y-%m-%d")
current_date=$(date +"%Y-%m-%d")
used_days=$(( ( $(date -d "$current_date" +%s) - $(date -d "$account_creation_date" +%s) ) / 86400 ))
if [[ $used_days -gt $expiration_days ]]; then
used_days=$expiration_days
fi
echo -e "${green}User Details:${NC}"
echo -e "Username: $username"
echo -e "Password: $password"
echo -e "Total Traffic: $max_download_gb GB"
echo -e "Total Usage: $total_usage_gb GB"
echo -e "Time Expiration: $expiration_date ($used_days/$expiration_days Days)"
echo -e "Blocked: $blocked"
echo -e "Status: $status"
}
hysteria2_list_users_handler() {
users_json=$(python3 $CLI_PATH list-users 2>/dev/null)
if [ $? -ne 0 ] || [ -z "$users_json" ]; then
echo -e "${red}Error:${NC} Failed to list users."
return 1
fi
# Extract keys (usernames) from JSON
users_keys=$(echo "$users_json" | jq -r 'keys[]')
if [ -z "$users_keys" ]; then
echo -e "${red}Error:${NC} No users found."
return 1
fi
# Print headers
printf "%-20s %-20s %-15s %-20s %-30s %-10s\n" "Username" "Traffic Limit (GB)" "Expiration (Days)" "Creation Date" "Password" "Blocked"
# Print user details
for key in $users_keys; do
echo "$users_json" | jq -r --arg key "$key" '
"\($key) \(.[$key].max_download_bytes / 1073741824) \(.[$key].expiration_days) \(.[$key].account_creation_date) \(.[$key].password) \(.[$key].blocked)"' | \
while IFS= read -r line; do
IFS=' ' read -r username traffic_limit expiration_date creation_date password blocked <<< "$line"
printf "%-20s %-20s %-15s %-20s %-30s %-10s\n" "$username" "$traffic_limit" "$expiration_date" "$creation_date" "$password" "$blocked"
done
done
}
hysteria2_reset_user_handler() {
while true; do
read -p "Enter the username: " username
if [[ "$username" =~ ^[a-zA-Z0-9]+$ ]]; then
break
else
echo -e "${red}Error:${NC} Username can only contain letters and numbers."
fi
done
python3 $CLI_PATH reset-user --username "$username"
}
hysteria2_show_user_uri_handler() {
check_service_active() {
systemctl is-active --quiet "$1"
}
while true; do
read -p "Enter the username: " username
if [[ "$username" =~ ^[a-zA-Z0-9]+$ ]]; then
break
else
echo -e "${red}Error:${NC} Username can only contain letters and numbers."
fi
done
flags=""
if check_service_active "hysteria-singbox.service"; then
flags+=" -s"
fi
if check_service_active "hysteria-normal-sub.service"; then
flags+=" -n"
fi
if [[ -n "$flags" ]]; then
python3 $CLI_PATH show-user-uri -u "$username" -a -qr $flags
else
python3 $CLI_PATH show-user-uri -u "$username" -a -qr
fi
}
hysteria2_change_port_handler() {
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
python3 $CLI_PATH change-hysteria2-port --port "$port"
}
hysteria2_change_sni_handler() {
while true; do
read -p "Enter the new SNI (e.g., example.com): " sni
if [[ "$sni" =~ ^[a-zA-Z0-9.]+$ ]]; then
break
else
echo -e "${red}Error:${NC} SNI can only contain letters, numbers, and dots."
fi
done
python3 $CLI_PATH change-hysteria2-sni --sni "$sni"
if systemctl is-active --quiet hysteria-singbox.service; then
systemctl restart hysteria-singbox.service
fi
}
edit_ips() {
while true; do
echo "======================================"
echo " IP/Domain Address Manager "
echo "======================================"
echo "1. Change IPv4 or Domain"
echo "2. Change IPv6 or Domain"
echo "0. Back"
echo "======================================"
read -p "Enter your choice [0-2]: " choice
case $choice in
1)
read -p "Enter the new IPv4 address or domain: " new_ip4_or_domain
if [[ $new_ip4_or_domain =~ ^([0-9]{1,3}\.){3}[0-9]{1,3}$ ]]; then
if [[ $(echo "$new_ip4_or_domain" | awk -F. '{for (i=1;i<=NF;i++) if ($i>255) exit 1}') ]]; then
echo "Error: Invalid IPv4 address. Values must be between 0 and 255."
else
python3 "$CLI_PATH" ip-address --edit -4 "$new_ip4_or_domain"
echo "IPv4 address has been updated to $new_ip4_or_domain."
fi
elif [[ $new_ip4_or_domain =~ ^[a-zA-Z0-9.-]+$ ]] && [[ ! $new_ip4_or_domain =~ [/:] ]]; then
python3 "$CLI_PATH" ip-address --edit -4 "$new_ip4_or_domain"
echo "Domain has been updated to $new_ip4_or_domain."
else
echo "Error: Invalid IPv4 or domain format."
fi
break
;;
2)
read -p "Enter the new IPv6 address or domain: " new_ip6_or_domain
if [[ $new_ip6_or_domain =~ ^(([0-9a-fA-F]{1,4}:){7}([0-9a-fA-F]{1,4}|:)|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:))$ ]]; then
python3 "$CLI_PATH" ip-address --edit -6 "$new_ip6_or_domain"
echo "IPv6 address has been updated to $new_ip6_or_domain."
elif [[ $new_ip6_or_domain =~ ^[a-zA-Z0-9.-]+$ ]] && [[ ! $new_ip6_or_domain =~ [/:] ]]; then
python3 "$CLI_PATH" ip-address --edit -6 "$new_ip6_or_domain"
echo "Domain has been updated to $new_ip6_or_domain."
else
echo "Error: Invalid IPv6 or domain format."
fi
break
;;
0)
break
;;
*)
echo "Invalid option. Please try again."
break
;;
esac
echo "======================================"
read -p "Press Enter to continue..."
done
}
hysteria_upgrade(){
bash <(curl https://raw.githubusercontent.com/ReturnFI/Blitz/main/upgrade.sh)
}
warp_configure_handler() {
local service_name="wg-quick@wgcf.service"
if systemctl is-active --quiet "$service_name"; then
echo -e "${cyan}=== WARP Status ===${NC}"
status_json=$(python3 $CLI_PATH warp-status)
all_traffic=$(echo "$status_json" | grep -o '"all_traffic_via_warp": *[^,}]*' | cut -d':' -f2 | tr -d ' "')
popular_sites=$(echo "$status_json" | grep -o '"popular_sites_via_warp": *[^,}]*' | cut -d':' -f2 | tr -d ' "')
domestic_sites_via_warp=$(echo "$status_json" | grep -o '"domestic_sites_via_warp": *[^,}]*' | cut -d':' -f2 | tr -d ' "')
block_adult=$(echo "$status_json" | grep -o '"block_adult_content": *[^,}]*' | cut -d':' -f2 | tr -d ' "')
display_status() {
local label="$1"
local status_val="$2"
if [ "$status_val" = "true" ]; then
echo -e " ${green}${NC} $label: ${green}Enabled${NC}"
else
echo -e " ${red}${NC} $label: ${red}Disabled${NC}"
fi
}
display_status "All Traffic via WARP" "$all_traffic"
display_status "Popular Sites via WARP" "$popular_sites"
display_status "Domestic Sites via WARP" "$domestic_sites_via_warp"
display_status "Block Adult Content" "$block_adult"
echo -e "${cyan}==================${NC}"
echo
echo "Configure WARP Options (Toggle):"
echo "1. All traffic via WARP"
echo "2. Popular sites via WARP"
echo "3. Domestic sites (WARP/Reject)"
echo "4. Block adult content"
echo "5. WARP Status Profile (IP etc.)"
echo "6. Change WARP IP address"
echo "7. Switch to WARP Plus"
echo "8. Switch to Normal WARP"
echo "0. Cancel"
read -p "Select an option to toggle: " option
case $option in
1)
target_state=$([ "$all_traffic" = "true" ] && echo "off" || echo "on")
python3 $CLI_PATH configure-warp --set-all "$target_state" ;;
2)
target_state=$([ "$popular_sites" = "true" ] && echo "off" || echo "on")
python3 $CLI_PATH configure-warp --set-popular-sites "$target_state" ;;
3)
target_state=$([ "$domestic_sites_via_warp" = "true" ] && echo "off" || echo "on")
python3 $CLI_PATH configure-warp --set-domestic-sites "$target_state" ;;
4)
target_state=$([ "$block_adult" = "true" ] && echo "off" || echo "on")
python3 $CLI_PATH configure-warp --set-block-adult-sites "$target_state" ;;
5)
current_ip=$(python3 $CLI_PATH warp-status | grep -o '"ip": *"[^"]*"' | cut -d':' -f2- | tr -d '" ')
if [ -z "$current_ip" ]; then
current_ip=$(curl -s --interface wgcf --connect-timeout 1 http://v4.ident.me || echo "N/A")
fi
cd /etc/warp/ && wgcf status
echo
echo -e "${yellow}Warp IP:${NC} ${cyan}${current_ip}${NC}"
;;
6)
old_ip=$(curl -s --interface wgcf --connect-timeout 1 http://v4.ident.me || echo "N/A")
echo -e "${yellow}Current IP:${NC} ${cyan}$old_ip${NC}"
echo "Restarting $service_name to attempt IP change..."
systemctl restart "$service_name"
echo -n "Waiting for service to restart"
for i in {1..5}; do
echo -n "."
sleep 1
done
echo
new_ip=$(curl -s --interface wgcf --connect-timeout 1 http://v4.ident.me || echo "N/A")
echo -e "${yellow}New IP:${NC} ${green}$new_ip${NC}"
if [ "$old_ip" != "N/A" ] && [ "$new_ip" != "N/A" ] && [ "$old_ip" != "$new_ip" ]; then
echo -e "${green}✓ IP address changed successfully${NC}"
elif [ "$old_ip" = "$new_ip" ] && [ "$old_ip" != "N/A" ]; then
echo -e "${yellow}⚠ IP address remained the same${NC}"
else
echo -e "${red}✗ Could not verify IP change.${NC}"
fi
;;
7)
echo -e "${yellow}Switching to WARP Plus...${NC}"
read -p "Enter your WARP Plus license key: " warp_key
if [ -z "$warp_key" ]; then
echo -e "${red}Error: WARP Plus key is required.${NC}"
else
echo "Stopping WARP service..."
systemctl stop "$service_name" 2>/dev/null
cd /etc/warp/ || { echo -e "${red}Failed to change directory to /etc/warp/${NC}"; return 1; }
echo "Updating WARP Plus configuration..."
WGCF_LICENSE_KEY="$warp_key" wgcf update
if [ $? -eq 0 ]; then
echo "Starting WARP service..."
systemctl start "$service_name"
echo -e "${green}✓ Successfully switched to WARP Plus${NC}"
python3 "$CLI_PATH" restart-hysteria2 > /dev/null 2>&1
else
echo -e "${red}✗ Failed to update WARP Plus configuration${NC}"
systemctl start "$service_name"
fi
fi
;;
8)
echo -e "${yellow}Switching to Normal WARP...${NC}"
echo "This will create a new WARP account. Continue? (y/N)"
read -p "" confirm
if [[ "$confirm" =~ ^[Yy]$ ]]; then
echo "Stopping WARP service..."
systemctl stop "$service_name" 2>/dev/null
cd /etc/warp/ || { echo -e "${red}Failed to change directory to /etc/warp/${NC}"; return 1; }
echo "Creating new WARP account..."
rm -f wgcf-account.toml
yes | wgcf register
if [ $? -eq 0 ]; then
echo "Starting WARP service..."
systemctl start "$service_name"
echo -e "${green}✓ Successfully switched to Normal WARP with new account${NC}"
python3 "$CLI_PATH" restart-hysteria2 > /dev/null 2>&1
else
echo -e "${red}✗ Failed to register new WARP account${NC}"
systemctl start "$service_name"
fi
else
echo -e "${yellow}Operation canceled${NC}"
fi
;;
0) echo "WARP configuration canceled." ;;
*) echo -e "${red}Invalid option. Please try again.${NC}" ;;
esac
else
echo -e "${red}$service_name is not active. Please start the service before configuring WARP.${NC}"
fi
}
telegram_bot_handler() {
while true; do
echo -e "${cyan}1.${NC} Start Telegram bot service"
echo -e "${red}2.${NC} Stop Telegram bot service"
echo "0. Back"
read -p "Choose an option: " option
case $option in
1)
if systemctl is-active --quiet hysteria-telegram-bot.service; then
echo "The hysteria-telegram-bot.service is already active."
else
while true; do
read -e -p "Enter the Telegram bot token: " token
if [ -z "$token" ]; then
echo "Token cannot be empty. Please try again."
else
break
fi
done
while true; do
read -e -p "Enter the admin IDs (comma-separated): " admin_ids
if [[ ! "$admin_ids" =~ ^[0-9,]+$ ]]; then
echo "Admin IDs can only contain numbers and commas. Please try again."
elif [ -z "$admin_ids" ]; then
echo "Admin IDs cannot be empty. Please try again."
else
break
fi
done
python3 $CLI_PATH telegram -a start -t "$token" -aid "$admin_ids"
fi
;;
2)
python3 $CLI_PATH telegram -a stop
;;
0)
break
;;
*)
echo "Invalid option. Please try again."
;;
esac
done
}
singbox_handler() {
while true; do
echo -e "${cyan}Merged with Normal-Sub sublink.${NC}"
# echo -e "${cyan}1.${NC} Start Singbox service"
echo -e "${red}2.${NC} Stop Singbox service"
echo "0. Back"
read -p "Choose an option: " option
case $option in
# 1)
# if systemctl is-active --quiet hysteria-singbox.service; then
# echo "The hysteria-singbox.service is already active."
# else
# while true; do
# read -e -p "Enter the domain name for the SSL certificate: " domain
# if [ -z "$domain" ]; then
# echo "Domain name cannot be empty. Please try again."
# else
# break
# fi
# done
# while true; do
# read -e -p "Enter the port number for the service: " port
# if [ -z "$port" ]; then
# echo "Port number cannot be empty. Please try again."
# elif ! [[ "$port" =~ ^[0-9]+$ ]]; then
# echo "Port must be a number. Please try again."
# else
# break
# fi
# done
# python3 $CLI_PATH singbox -a start -d "$domain" -p "$port"
# fi
# ;;
2)
if ! systemctl is-active --quiet hysteria-singbox.service; then
echo "The hysteria-singbox.service is already inactive."
else
python3 $CLI_PATH singbox -a stop
fi
;;
0)
break
;;
*)
echo "Invalid option. Please try again."
;;
esac
done
}
normalsub_handler() {
while true; do
echo -e "${cyan}1.${NC} Start Normal-Sub service"
echo -e "${red}2.${NC} Stop Normal-Sub service"
echo -e "${yellow}3.${NC} Change SUBPATH"
echo "0. Back"
read -p "Choose an option: " option
case $option in
1)
if systemctl is-active --quiet hysteria-normal-sub.service; then
echo "The hysteria-normal-sub.service is already active."
else
while true; do
read -e -p "Enter the domain name for the SSL certificate: " domain
if [ -z "$domain" ]; then
echo "Domain name cannot be empty. Please try again."
else
break
fi
done
while true; do
read -e -p "Enter the port number for the service: " port
if [ -z "$port" ]; then
echo "Port number cannot be empty. Please try again."
elif ! [[ "$port" =~ ^[0-9]+$ ]]; then
echo "Port must be a number. Please try again."
else
break
fi
done
python3 $CLI_PATH normal-sub -a start -d "$domain" -p "$port"
fi
;;
2)
if ! systemctl is-active --quiet hysteria-normal-sub.service; then
echo "The hysteria-normal-sub.service is already inactive."
else
python3 $CLI_PATH normal-sub -a stop
fi
;;
3)
if ! systemctl is-active --quiet hysteria-normal-sub.service; then
echo "Error: The hysteria-normal-sub.service is not active. Start the service first."
continue
fi
while true; do
read -e -p "Enter new SUBPATH (Must include Uppercase, Lowercase, and Numbers): " subpath
if [[ -z "$subpath" ]]; then
echo "Error: SUBPATH cannot be empty. Please try again."
elif ! [[ "$subpath" =~ [A-Z] ]] || ! [[ "$subpath" =~ [a-z] ]] || ! [[ "$subpath" =~ [0-9] ]]; then
echo "Error: SUBPATH must include at least one uppercase letter, one lowercase letter, and one number."
else
python3 $CLI_PATH normal-sub -a edit_subpath -sp "$subpath"
# echo "SUBPATH updated successfully!"
break
fi
done
;;
0)
break
;;
*)
echo "Invalid option. Please try again."
;;
esac
done
}
webpanel_handler() {
service_status=$(python3 "$CLI_PATH" get-webpanel-services-status)
echo -e "${cyan}Services Status:${NC}"
echo "$service_status"
echo ""
while true; do
echo -e "${cyan}1.${NC} Start WebPanel service"
echo -e "${red}2.${NC} Stop WebPanel service"
echo -e "${cyan}3.${NC} Get WebPanel URL"
echo -e "${cyan}4.${NC} Show API Token"
echo -e "${yellow}5.${NC} Reset WebPanel Credentials"
echo "0. Back"
read -p "Choose an option: " option
case $option in
1)
if systemctl is-active --quiet hysteria-webpanel.service; then
echo "The hysteria-webpanel.service is already active."
else
while true; do
read -e -p "Enter the domain name for the SSL certificate: " domain
if [ -z "$domain" ]; then
echo "Domain name cannot be empty. Please try again."
else
break
fi
done
while true; do
read -e -p "Enter the port number for the service: " port
if [ -z "$port" ]; then
echo "Port number cannot be empty. Please try again."
elif ! [[ "$port" =~ ^[0-9]+$ ]]; then
echo "Port must be a number. Please try again."
else
break
fi
done
while true; do
read -e -p "Enter the admin username: " admin_username
if [ -z "$admin_username" ]; then
echo "Admin username cannot be empty. Please try again."
else
break
fi
done
while true; do
read -e -p "Enter the admin password: " admin_password
if [ -z "$admin_password" ]; then
echo "Admin password cannot be empty. Please try again."
else
break
fi
done
python3 $CLI_PATH webpanel -a start -d "$domain" -p "$port" -au "$admin_username" -ap "$admin_password"
fi
;;
2)
if ! systemctl is-active --quiet hysteria-webpanel.service; then
echo "The hysteria-webpanel.service is already inactive."
else
python3 $CLI_PATH webpanel -a stop
fi
;;
3)
url=$(python3 $CLI_PATH get-webpanel-url)
echo "-------------------------------"
echo "$url"
echo "-------------------------------"
;;
4)
api_token=$(python3 $CLI_PATH get-webpanel-api-token)
echo "-------------------------------"
echo "$api_token"
echo "-------------------------------"
;;
5)
if ! systemctl is-active --quiet hysteria-webpanel.service; then
echo -e "${red}WebPanel service is not running. Cannot reset credentials.${NC}"
else
read -e -p "Enter new admin username (leave blank to keep current): " new_username
read -e -p "Enter new admin password (leave blank to keep current): " new_password
echo
if [ -z "$new_username" ] && [ -z "$new_password" ]; then
echo -e "${yellow}No changes specified. Aborting.${NC}"
else
local cmd_args=("-u" "$new_username")
if [ -n "$new_password" ]; then
cmd_args+=("-p" "$new_password")
fi
if [ -z "$new_username" ]; then
cmd_args=()
if [ -n "$new_password" ]; then
cmd_args+=("-p" "$new_password")
fi
fi
echo "Attempting to reset credentials..."
python3 "$CLI_PATH" reset-webpanel-creds "${cmd_args[@]}"
fi
fi
;;
0)
break
;;
*)
echo "Invalid option. Please try again."
;;
esac
done
}
obfs_handler() {
while true; do
echo -e "${cyan}1.${NC} Remove Obfs"
echo -e "${red}2.${NC} Generating new Obfs"
echo "0. Back"
read -p "Choose an option: " option
case $option in
1)
python3 $CLI_PATH manage_obfs -r
;;
2)
python3 $CLI_PATH manage_obfs -g
;;
0)
break
;;
*)
echo "Invalid option. Please try again."
;;
esac
done
}
geo_update_handler() {
echo "Configure Geo Update Options:"
echo "1. Update Iran Geo Files"
echo "2. Update China Geo Files"
echo "3. Update Russia Geo Files"
echo "4. Check Current Geo Files"
echo "0. Cancel"
read -p "Select an option: " option
case $option in
1)
echo "Updating Iran Geo Files..."
python3 $CLI_PATH update-geo --country iran
;;
2)
echo "Updating China Geo Files..."
python3 $CLI_PATH update-geo --country china
;;
3)
echo "Updating Russia Geo Files..."
python3 $CLI_PATH update-geo --country russia
;;
4)
echo "Current Geo Files Information:"
echo "--------------------------"
if [ -f "/etc/hysteria/geosite.dat" ]; then
echo "GeoSite File:"
ls -lh /etc/hysteria/geosite.dat
echo "Last modified: $(stat -c %y /etc/hysteria/geosite.dat)"
else
echo "GeoSite file not found!"
fi
echo
if [ -f "/etc/hysteria/geoip.dat" ]; then
echo "GeoIP File:"
ls -lh /etc/hysteria/geoip.dat
echo "Last modified: $(stat -c %y /etc/hysteria/geoip.dat)"
else
echo "GeoIP file not found!"
fi
;;
0)
echo "Geo update configuration canceled."
;;
*)
echo "Invalid option. Please try again."
;;
esac
}
masquerade_handler() {
while true; do
echo -e "${cyan}1.${NC} Enable Masquerade"
echo -e "${red}2.${NC} Remove Masquerade"
echo "0. Back"
read -p "Choose an option: " option
case $option in
1)
if systemctl is-active --quiet hysteria-webpanel.service; then
echo -e "${red}Error:${NC} Masquerade cannot be enabled because hysteria-webpanel.service is running."
else
read -p "Enter the URL for rewriteHost: " url
if [ -z "$url" ]; then
echo "Error: URL cannot be empty. Please try again."
else
python3 $CLI_PATH masquerade -e "$url"
fi
fi
;;
2)
python3 $CLI_PATH masquerade -r
;;
0)
break
;;
*)
echo "Invalid option. Please try again."
;;
esac
done
}
ip_limit_handler() {
while true; do
echo -e "${cyan}1.${NC} Start IP Limiter Service"
echo -e "${red}2.${NC} Stop IP Limiter Service"
echo -e "${yellow}3.${NC} Change IP Limiter Configuration"
echo "0. Back"
read -p "Choose an option: " option
case $option in
1)
if systemctl is-active --quiet hysteria-ip-limit.service; then
echo "The hysteria-ip-limit.service is already active."
else
while true; do
read -e -p "Enter Block Duration (seconds, default: 60): " block_duration
block_duration=${block_duration:-60} # Default to 60 if empty
if ! [[ "$block_duration" =~ ^[0-9]+$ ]]; then
echo "Invalid Block Duration. Please enter a number."
else
break
fi
done
while true; do
read -e -p "Enter Max IPs per User (default: 1): " max_ips
max_ips=${max_ips:-1} # Default to 1 if empty
if ! [[ "$max_ips" =~ ^[0-9]+$ ]]; then
echo "Invalid Max IPs. Please enter a number."
else
break
fi
done
python3 $CLI_PATH config-ip-limit --block-duration "$block_duration" --max-ips "$max_ips"
python3 $CLI_PATH start-ip-limit
fi
;;
2)
if ! systemctl is-active --quiet hysteria-ip-limit.service; then
echo "The hysteria-ip-limit.service is already inactive."
else
python3 $CLI_PATH stop-ip-limit
fi
;;
3)
block_duration=""
max_ips=""
updated=false
while true; do
read -e -p "Enter New Block Duration (seconds, current: $(grep '^BLOCK_DURATION=' /etc/hysteria/.configs.env | cut -d'=' -f2), leave empty to keep current): " input_block_duration
if [[ -n "$input_block_duration" ]] && ! [[ "$input_block_duration" =~ ^[0-9]+$ ]]; then
echo "Invalid Block Duration. Please enter a number or leave empty."
else
if [[ -n "$input_block_duration" ]]; then
block_duration="$input_block_duration"
updated=true
fi
break
fi
done
while true; do
read -e -p "Enter New Max IPs per User (current: $(grep '^MAX_IPS=' /etc/hysteria/.configs.env | cut -d'=' -f2), leave empty to keep current): " input_max_ips
if [[ -n "$input_max_ips" ]] && ! [[ "$input_max_ips" =~ ^[0-9]+$ ]]; then
echo "Invalid Max IPs. Please enter a number or leave empty."
else
if [[ -n "$input_max_ips" ]]; then
max_ips="$input_max_ips"
updated=true
fi
break
fi
done
if [[ "$updated" == "true" ]]; then
python3 $CLI_PATH config-ip-limit --block-duration "$block_duration" --max-ips "$max_ips"
else
echo "No changes to IP Limiter configuration were provided."
fi
;;
0)
break
;;
*)
echo "Invalid option. Please try again."
;;
esac
done
}
# Function to display the main menu
display_main_menu() {
clear
tput setaf 7 ; tput setab 4 ; tput bold
echo -e "◇────────────────🚀 Welcome To Blitz Panel 🚀─────────────────◇"
tput sgr0
echo -e "${LPurple}◇──────────────────────────────────────────────────────────────────────◇${NC}"
printf "\033[0;32m• OS: \033[0m%-25s \033[0;32m• ARCH: \033[0m%-25s\n" "$OS" "$ARCH"
printf "\033[0;32m• ISP: \033[0m%-25s \033[0;32m• CPU: \033[0m%-25s\n" "$ISP" "$CPU"
printf "\033[0;32m• IP: \033[0m%-25s \033[0;32m• RAM: \033[0m%-25s\n" "$IP" "$RAM"
echo -e "${LPurple}◇──────────────────────────────────────────────────────────────────────◇${NC}"
check_core_version
check_version
echo -e "${LPurple}◇──────────────────────────────────────────────────────────────────────◇${NC}"
echo -e "${yellow} ☼ Services Status ☼ ${NC}"
echo -e "${LPurple}◇──────────────────────────────────────────────────────────────────────◇${NC}"
check_services
echo -e "${LPurple}◇──────────────────────────────────────────────────────────────────────◇${NC}"
echo -e "${yellow} ☼ Main Menu ☼ ${NC}"
echo -e "${LPurple}◇──────────────────────────────────────────────────────────────────────◇${NC}"
echo -e "${green}[1] ${NC}↝ Hysteria2 Menu"
echo -e "${cyan}[2] ${NC}↝ Advance Menu"
echo -e "${cyan}[3] ${NC}↝ Update Panel"
echo -e "${red}[0] ${NC}↝ Exit"
echo -e "${LPurple}◇──────────────────────────────────────────────────────────────────────◇${NC}"
echo -ne "${yellow}➜ Enter your option: ${NC}"
}
# Function to handle main menu options
main_menu() {
clear
local choice
while true; do
get_system_info
display_main_menu
read -r choice
case $choice in
1) hysteria2_menu ;;
2) advance_menu ;;
3) hysteria_upgrade ;;
0) exit 0 ;;
*) echo "Invalid option. Please try again." ;;
esac
echo
read -rp "Press Enter to continue..."
done
}
# Function to display the Blitz menu
display_hysteria2_menu() {
clear
echo -e "${LPurple}◇──────────────────────────────────────────────────────────────────────◇${NC}"
echo -e "${yellow} ☼ Blitz Menu ☼ ${NC}"
echo -e "${LPurple}◇──────────────────────────────────────────────────────────────────────◇${NC}"
echo -e "${green}[1] ${NC}↝ Install and Configure Hysteria2"
echo -e "${cyan}[2] ${NC}↝ Add User"
echo -e "${cyan}[3] ${NC}↝ Edit User"
echo -e "${cyan}[4] ${NC}↝ Reset User"
echo -e "${cyan}[5] ${NC}↝ Remove User"
echo -e "${cyan}[6] ${NC}↝ Get User"
echo -e "${cyan}[7] ${NC}↝ List Users"
echo -e "${cyan}[8] ${NC}↝ Check Traffic Status"
echo -e "${cyan}[9] ${NC}↝ Show User URI"
echo -e "${red}[0] ${NC}↝ Back to Main Menu"
echo -e "${LPurple}◇──────────────────────────────────────────────────────────────────────◇${NC}"
echo -ne "${yellow}➜ Enter your option: ${NC}"
}
# Function to handle Hysteria2 menu options
hysteria2_menu() {
clear
local choice
while true; do
get_system_info
display_hysteria2_menu
read -r choice
case $choice in
1) hysteria2_install_handler ;;
2) hysteria2_add_user_handler ;;
3) hysteria2_edit_user_handler ;;
4) hysteria2_reset_user_handler ;;
5) hysteria2_remove_user_handler ;;
6) hysteria2_get_user_handler ;;
7) hysteria2_list_users_handler ;;
8) python3 $CLI_PATH traffic-status ;;
9) hysteria2_show_user_uri_handler ;;
0) return ;;
*) echo "Invalid option. Please try again." ;;
esac
echo
read -rp "Press Enter to continue..."
done
}
# Function to get Advance menu
display_advance_menu() {
clear
echo -e "${LPurple}◇──────────────────────────────────────────────────────────────────────◇${NC}"
echo -e "${yellow} ☼ Advance Menu ☼ ${NC}"
echo -e "${LPurple}◇──────────────────────────────────────────────────────────────────────◇${NC}"
echo -e "${green}[1] ${NC}↝ Install TCP Brutal"
echo -e "${green}[2] ${NC}↝ Install WARP"
echo -e "${cyan}[3] ${NC}↝ Configure WARP"
echo -e "${red}[4] ${NC}↝ Uninstall WARP"
echo -e "${green}[5] ${NC}↝ Telegram Bot"
echo -e "${green}[6] ${NC}↝ SingBox SubLink(${red}Deprecated${NC})"
echo -e "${green}[7] ${NC}↝ Normal-SUB SubLink"
echo -e "${green}[8] ${NC}↝ Web Panel"
echo -e "${cyan}[9] ${NC}↝ Change Port Hysteria2"
echo -e "${cyan}[10] ${NC}↝ Change SNI Hysteria2"
echo -e "${cyan}[11] ${NC}↝ Manage OBFS"
echo -e "${cyan}[12] ${NC}↝ Change IPs(4-6)"
echo -e "${cyan}[13] ${NC}↝ Update geo Files"
echo -e "${cyan}[14] ${NC}↝ Manage Masquerade"
echo -e "${cyan}[15] ${NC}↝ Restart Hysteria2"
echo -e "${cyan}[16] ${NC}↝ Update Core Hysteria2"
echo -e "${cyan}[17] ${NC}↝ IP Limiter Menu"
echo -e "${red}[18] ${NC}↝ Uninstall Hysteria2"
echo -e "${red}[0] ${NC}↝ Back to Main Menu"
echo -e "${LPurple}◇──────────────────────────────────────────────────────────────────────◇${NC}"
echo -ne "${yellow}➜ Enter your option: ${NC}"
}
# Function to handle Advance menu options
advance_menu() {
clear
local choice
while true; do
display_advance_menu
read -r choice
case $choice in
1) python3 $CLI_PATH install-tcp-brutal ;;
2) python3 $CLI_PATH install-warp ;;
3) warp_configure_handler ;;
4) python3 $CLI_PATH uninstall-warp ;;
5) telegram_bot_handler ;;
6) singbox_handler ;;
7) normalsub_handler ;;
8) webpanel_handler ;;
9) hysteria2_change_port_handler ;;
10) hysteria2_change_sni_handler ;;
11) obfs_handler ;;
12) edit_ips ;;
13) geo_update_handler ;;
14) masquerade_handler ;;
15) python3 $CLI_PATH restart-hysteria2 ;;
16) python3 $CLI_PATH update-hysteria2 ;;
17) ip_limit_handler ;;
18) python3 $CLI_PATH uninstall-hysteria2 ;;
0) return ;;
*) echo "Invalid option. Please try again." ;;
esac
echo
read -rp "Press Enter to continue..."
done
}
# Main function to run the script
define_colors
main_menu