diff --git a/VERSION b/VERSION index b003284..a45be46 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -0.2.7 +0.2.8 diff --git a/core/cli.py b/core/cli.py index 408740c..2b6312a 100644 --- a/core/cli.py +++ b/core/cli.py @@ -29,6 +29,7 @@ class Command(Enum): RESET_USER = os.path.join(SCRIPT_DIR, 'hysteria2', 'reset_user.sh') REMOVE_USER = os.path.join(SCRIPT_DIR, 'hysteria2', 'remove_user.sh') SHOW_USER_URI = os.path.join(SCRIPT_DIR, 'hysteria2', 'show_user_uri.sh') + MANAGE_OBFS = os.path.join(SCRIPT_DIR, 'hysteria2', 'manage_obfs.sh') TRAFFIC_STATUS = 'traffic.py' # won't be call directly (it's a python module) LIST_USERS = os.path.join(SCRIPT_DIR, 'hysteria2', 'list_users.sh') SERVER_INFO = os.path.join(SCRIPT_DIR, 'hysteria2', 'server_info.sh') @@ -40,6 +41,7 @@ class Command(Enum): INSTALL_WARP = os.path.join(SCRIPT_DIR, 'warp', 'install.sh') UNINSTALL_WARP = os.path.join(SCRIPT_DIR, 'warp', 'uninstall.sh') CONFIGURE_WARP = os.path.join(SCRIPT_DIR, 'warp', 'configure.sh') + STATUS_WARP = os.path.join(SCRIPT_DIR, 'warp', 'status.sh') # region utils @@ -247,6 +249,23 @@ def backup_hysteria(): except subprocess.CalledProcessError as e: click.echo(f"Backup failed: {e.output.decode()}", err=True) +@cli.command('manage_obfs') +@click.option('--remove', '-r', is_flag=True, help="Remove 'obfs' from config.json.") +@click.option('--generate', '-g', is_flag=True, help="Generate new 'obfs' in config.json.") +def manage_obfs(remove, generate): + """Manage 'obfs' in Hysteria2 configuration.""" + if remove and generate: + click.echo("Error: You cannot use both --remove and --generate at the same time.") + return + elif remove: + click.echo("Removing 'obfs' from config.json...") + run_cmd(['bash', Command.MANAGE_OBFS.value, '--remove']) + elif generate: + click.echo("Generating 'obfs' in config.json...") + run_cmd(['bash', Command.MANAGE_OBFS.value, '--generate']) + else: + click.echo("Error: Please specify either --remove or --generate.") + # endregion # region advanced menu @@ -302,6 +321,12 @@ def configure_warp(all: bool, popular_sites: bool, domestic_sites: bool, block_a run_cmd(cmd_args) +@cli.command('warp-status') +def warp_status(): + output = run_cmd(['bash', Command.STATUS_WARP.value]) + if output: + print(output) + @cli.command('telegram') @click.option('--action', '-a', required=True, help='Action to perform: start or stop', type=click.Choice(['start', 'stop'], case_sensitive=False)) @click.option('--token', '-t', required=False, help='Token for running the telegram bot', type=str) diff --git a/core/scripts/hysteria2/manage_obfs.sh b/core/scripts/hysteria2/manage_obfs.sh new file mode 100644 index 0000000..0d7ef95 --- /dev/null +++ b/core/scripts/hysteria2/manage_obfs.sh @@ -0,0 +1,42 @@ +#!/bin/bash + +source /etc/hysteria/core/scripts/path.sh + +remove_obfs() { + if jq 'has("obfs")' "$CONFIG_FILE" | grep -q true; then + jq 'del(.obfs)' "$CONFIG_FILE" > temp_config.json && mv temp_config.json "$CONFIG_FILE" + echo "Successfully removed 'obfs' from config.json." + else + echo "'obfs' section not found in config.json." + fi + + python3 "$CLI_PATH" restart-hysteria2 > /dev/null 2>&1 +} + +generate_obfs() { + obfspassword=$(pwgen -s 32 1) + + if jq 'has("obfs")' "$CONFIG_FILE" | grep -q true; then + echo "'obfs' section already exists. Replacing it with a new one." + jq 'del(.obfs)' "$CONFIG_FILE" > temp_config.json && mv temp_config.json "$CONFIG_FILE" + fi + + jq '. + {obfs: {type: "salamander", salamander: {password: "'"$obfspassword"'"}}}' "$CONFIG_FILE" > temp_config.json && mv temp_config.json "$CONFIG_FILE" + + if [ $? -eq 0 ]; then + echo "Successfully added 'obfs' to config.json with password: $obfspassword" + else + echo "Error: Failed to add 'obfs' to config.json." + fi + + python3 "$CLI_PATH" restart-hysteria2 > /dev/null 2>&1 +} + +if [[ $1 == "--remove" || $1 == "-r" ]]; then + remove_obfs +elif [[ $1 == "--generate" || $1 == "-g" ]]; then + generate_obfs +else + echo "Usage: $0 --remove|-r | --generate|-g" + exit 1 +fi diff --git a/core/scripts/hysteria2/show_user_uri.sh b/core/scripts/hysteria2/show_user_uri.sh index c8c6bbf..5761a7d 100644 --- a/core/scripts/hysteria2/show_user_uri.sh +++ b/core/scripts/hysteria2/show_user_uri.sh @@ -25,7 +25,6 @@ get_normalsub_domain_and_port() { fi } - show_uri() { if [ -f "$USERS_FILE" ]; then if systemctl is-active --quiet hysteria-server.service; then @@ -60,15 +59,23 @@ show_uri() { authpassword=$(jq -r ".\"$username\".password" "$USERS_FILE") port=$(jq -r '.listen' "$CONFIG_FILE" | cut -d':' -f2) sha256=$(jq -r '.tls.pinSHA256' "$CONFIG_FILE") - obfspassword=$(jq -r '.obfs.salamander.password' "$CONFIG_FILE") + obfspassword=$(jq -r '.obfs.salamander.password // empty' "$CONFIG_FILE") generate_uri() { local ip_version=$1 local ip=$2 - if [ "$ip_version" -eq 4 ]; then - echo "hy2://$username%3A$authpassword@$ip:$port?obfs=salamander&obfs-password=$obfspassword&pinSHA256=$sha256&insecure=1&sni=$SNI#$username-IPv4" - elif [ "$ip_version" -eq 6 ]; then - echo "hy2://$username%3A$authpassword@[$ip]:$port?obfs=salamander&obfs-password=$obfspassword&pinSHA256=$sha256&insecure=1&sni=$SNI#$username-IPv6" + if [ -n "$obfspassword" ]; then + if [ "$ip_version" -eq 4 ]; then + echo "hy2://$username%3A$authpassword@$ip:$port?obfs=salamander&obfs-password=$obfspassword&pinSHA256=$sha256&insecure=1&sni=$SNI#$username-IPv4" + elif [ "$ip_version" -eq 6 ]; then + echo "hy2://$username%3A$authpassword@[$ip]:$port?obfs=salamander&obfs-password=$obfspassword&pinSHA256=$sha256&insecure=1&sni=$SNI#$username-IPv6" + fi + else + if [ "$ip_version" -eq 4 ]; then + echo "hy2://$username%3A$authpassword@$ip:$port?pinSHA256=$sha256&insecure=1&sni=$SNI#$username-IPv4" + elif [ "$ip_version" -eq 6 ]; then + echo "hy2://$username%3A$authpassword@[$ip]:$port?pinSHA256=$sha256&insecure=1&sni=$SNI#$username-IPv6" + fi fi } diff --git a/core/scripts/utils.sh b/core/scripts/utils.sh index 8cfa96b..cbb1893 100644 --- a/core/scripts/utils.sh +++ b/core/scripts/utils.sh @@ -60,4 +60,22 @@ load_hysteria2_env() { echo "Error: configs.env file not found. Using default SNI 'bts.com'." SNI="bts.com" fi -} \ No newline at end of file +} + +check_services() { + declare -A service_names=( + ["hysteria-server.service"]="Hysteria2" + ["normalsub.service"]="Normal Subscription" + ["singbox.service"]="Singbox Subscription" + ["hysteria-bot.service"]="Hysteria Telegram Bot" + ["wg-quick@wgcf.service"]="WireGuard (WARP)" + ) + + for service in "${!service_names[@]}"; do + if systemctl is-active --quiet "$service"; then + echo -e "${NC}${service_names[$service]}:${green} Active${NC}" + else + echo -e "${NC}${service_names[$service]}:${red} Inactive${NC}" + fi + done +} diff --git a/core/scripts/warp/status.sh b/core/scripts/warp/status.sh new file mode 100644 index 0000000..18a13f2 --- /dev/null +++ b/core/scripts/warp/status.sh @@ -0,0 +1,34 @@ +source /etc/hysteria/core/scripts/utils.sh +source /etc/hysteria/core/scripts/path.sh + +check_warp_configuration() { + echo "--------------------------------" + echo -e "${LPurple}Current WARP Configuration: ${NC}" + + if jq -e '.acl.inline[]? | select(test("warps\\(all\\)"))' "$CONFIG_FILE" > /dev/null; then + echo -e "${cyan}All traffic:${NC} ${green}Active${NC}" + else + echo -e "${cyan}All traffic:${NC} ${red}Inactive${NC}" + fi + + if jq -e '.acl.inline[]? | select(test("warps\\(geosite:google\\)")) or select(test("warps\\(geoip:google\\)")) or select(test("warps\\(geosite:netflix\\)")) or select(test("warps\\(geosite:spotify\\)")) or select(test("warps\\(geosite:openai\\)")) or select(test("warps\\(geoip:openai\\)"))' "$CONFIG_FILE" > /dev/null; then + echo -e "${cyan}Popular sites (Google, Netflix, etc.):${NC} ${green}Active${NC}" + else + echo -e "${cyan}Popular sites (Google, Netflix, etc.):${NC} ${red}Inactive${NC}" + fi + + if jq -e '.acl.inline[]? | select(test("warps\\(geosite:ir\\)")) or select(test("warps\\(geoip:ir\\)"))' "$CONFIG_FILE" > /dev/null; then + echo -e "${cyan}Domestic sites (geosite:ir, geoip:ir):${NC} ${green}Active${NC}" + else + echo -e "${cyan}Domestic sites (geosite:ir, geoip:ir):${NC} ${red}Inactive${NC}" + fi + + if jq -e '.acl.inline[]? | select(test("reject\\(geosite:category-porn\\)"))' "$CONFIG_FILE" > /dev/null; then + echo -e "${cyan}Block adult content:${NC} ${green}Active${NC}" + else + echo -e "${cyan}Block adult content:${NC} ${red}Inactive${NC}" + fi + echo "--------------------------------" +} +define_colors +check_warp_configuration diff --git a/menu.sh b/menu.sh index df177ad..c81c816 100644 --- a/menu.sh +++ b/menu.sh @@ -262,6 +262,7 @@ warp_configure_handler() { local service_name="wg-quick@wgcf.service" if systemctl is-active --quiet "$service_name"; then + python3 $CLI_PATH warp-status echo "Configure WARP Options:" echo "1. Use WARP for all traffic" echo "2. Use WARP for popular sites" @@ -465,6 +466,31 @@ normalsub_handler() { 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 +} + # Function to display the main menu display_main_menu() { clear @@ -478,6 +504,7 @@ display_main_menu() { echo -e "${LPurple}◇──────────────────────────────────────────────────────────────────────◇${NC}" check_version + check_services echo -e "${LPurple}◇──────────────────────────────────────────────────────────────────────◇${NC}" echo -e "${yellow} ☼ Main Menu ☼ ${NC}" @@ -578,8 +605,10 @@ display_advance_menu() { echo -e "${green}[7] ${NC}↝ Normal-SUB SubLink" echo -e "${cyan}[8] ${NC}↝ Change Port Hysteria2" echo -e "${cyan}[9] ${NC}↝ Change SNI Hysteria2" - echo -e "${cyan}[10] ${NC}↝ Update Core Hysteria2" - echo -e "${red}[11] ${NC}↝ Uninstall Hysteria2" + echo -e "${cyan}[10] ${NC}↝ Manage OBFS" + echo -e "${cyan}[11] ${NC}↝ Restart Hysteria2" + echo -e "${cyan}[12] ${NC}↝ Update Core Hysteria2" + echo -e "${red}[13] ${NC}↝ Uninstall Hysteria2" echo -e "${red}[0] ${NC}↝ Back to Main Menu" echo -e "${LPurple}◇──────────────────────────────────────────────────────────────────────◇${NC}" echo -ne "${yellow}➜ Enter your option: ${NC}" @@ -602,8 +631,10 @@ advance_menu() { 7) normalsub_handler ;; 8) hysteria2_change_port_handler ;; 9) hysteria2_change_sni_handler ;; - 10) python3 $CLI_PATH update-hysteria2 ;; - 11) python3 $CLI_PATH uninstall-hysteria2 ;; + 10) obfs_handler ;; + 11) python3 $CLI_PATH RESTART_HYSTERIA2 ;; + 12) python3 $CLI_PATH update-hysteria2 ;; + 13) python3 $CLI_PATH uninstall-hysteria2 ;; 0) return ;; *) echo "Invalid option. Please try again." ;; esac