diff --git a/changelog b/changelog index 5e0cc37..1ffd1cb 100644 --- a/changelog +++ b/changelog @@ -1,13 +1,18 @@ ### API-CLI -1. Added get_hysteria2_port and get_hysteria2_sni in cli_api +1. Add: get_hysteria2_port and get_hysteria2_sni in cli_api 2. Chg: API function names -3. Restart hysteria-server.service after updating config file through API +3. Fix: Restart hysteria-server.service after updating config file through API ### WebPanel 1. Add: Interact with users when config file restored in config.html -2. Added documents and logo +2. Add: documents and logo 3. Add: Change port & Fill sni domain field on loading DOM & Adopt previous +4. Chg: Change Webpanel Port +5. Fix: blocked path ### Main -1. Restart Caddy service -2. Improve Hysteria2 uninstallation script for complete removal +1. Fix: Restart Caddy service +2. Fix: Improve Hysteria2 uninstallation script for complete removal +3. Fix: Skip missing IPs while generating URI and QR codes +4. Add: Use kernel for UUID generation and Removed uuid-runtime dependency +5. Add: Userinfo on normalsub diff --git a/core/scripts/hysteria2/install.sh b/core/scripts/hysteria2/install.sh index a68f525..ed2e466 100644 --- a/core/scripts/hysteria2/install.sh +++ b/core/scripts/hysteria2/install.sh @@ -53,7 +53,7 @@ EOF echo "Generating passwords and UUID..." obfspassword=$(pwgen -s 32 1) - UUID=$(uuidgen) + UUID=$(cat /proc/sys/kernel/random/uuid) chown hysteria:hysteria /etc/hysteria/ca.key /etc/hysteria/ca.crt chmod 640 /etc/hysteria/ca.key /etc/hysteria/ca.crt diff --git a/core/scripts/normalsub/normalsub.py b/core/scripts/normalsub/normalsub.py index 04b15bc..7739e0f 100644 --- a/core/scripts/normalsub/normalsub.py +++ b/core/scripts/normalsub/normalsub.py @@ -4,6 +4,7 @@ import subprocess import time import re import shlex +import json # Import the json module from aiohttp import web from aiohttp.web_middlewares import middleware from dotenv import load_dotenv @@ -62,11 +63,37 @@ async def handle(request): def get_user_uri(username): try: + user_info_command = [ + 'python3', + '/etc/hysteria/core/cli.py', + 'get-user', + '-u', username + ] + safe_user_info_command = [shlex.quote(arg) for arg in user_info_command] + user_info_output = subprocess.check_output(safe_user_info_command).decode() + user_info = json.loads(user_info_output) + + + upload = user_info.get('upload_bytes', 0) + download = user_info.get('download_bytes', 0) + total = user_info.get('max_download_bytes', 0) + creation_date_str = user_info.get('account_creation_date', '') + expiration_days = user_info.get('expiration_days', 0) + if creation_date_str and expiration_days > 0: + try: + creation_date = time.strptime(creation_date_str, "%Y-%m-%d") + expiration_timestamp = int(time.mktime(creation_date)) + (expiration_days * 24 * 60 * 60) + except ValueError: + expiration_timestamp = 0 + else: + expiration_timestamp = 0 + + # Get URI command = [ - 'python3', - '/etc/hysteria/core/cli.py', - 'show-user-uri', - '-u', username, + 'python3', + '/etc/hysteria/core/cli.py', + 'show-user-uri', + '-u', username, '-a' ] safe_command = [shlex.quote(arg) for arg in command] @@ -74,9 +101,20 @@ def get_user_uri(username): output = re.sub(r'IPv4:\s*', '', output) output = re.sub(r'IPv6:\s*', '', output) + subscription_info = ( + f"//subscription-userinfo: upload={upload}; download={download}; total={total}; expire={expiration_timestamp}\n" + ) + + profile_lines = f"//profile-title: {username}-Hysteria2 🚀\n//profile-update-interval: 1\n" + output = profile_lines + subscription_info + output + return output except subprocess.CalledProcessError: - raise RuntimeError("Failed to get URI.") + raise RuntimeError("Failed to get URI or user info.") + except json.JSONDecodeError: + raise RuntimeError("Failed to parse user info JSON.") + except ValueError: + raise RuntimeError("expiration_timestamp OR account_creation_date in config file is invalid") async def handle_404(request): print(f"404 Not Found: {request.path}") @@ -84,7 +122,7 @@ async def handle_404(request): if __name__ == '__main__': app = web.Application(middlewares=[rate_limit_middleware]) - + app.add_routes([web.get('/sub/normal/{username}', handle)]) app.router.add_route('*', '/sub/normal/{tail:.*}', handle_404) @@ -92,5 +130,5 @@ if __name__ == '__main__': ssl_context.load_cert_chain(certfile=CERTFILE, keyfile=KEYFILE) ssl_context.minimum_version = ssl.TLSVersion.TLSv1_2 ssl_context.set_ciphers('AES256+EECDH:AES256+EDH') - + web.run_app(app, port=PORT, ssl_context=ssl_context) diff --git a/core/scripts/webpanel/app.py b/core/scripts/webpanel/app.py index 9d04819..3458831 100644 --- a/core/scripts/webpanel/app.py +++ b/core/scripts/webpanel/app.py @@ -71,7 +71,7 @@ if __name__ == '__main__': config = Config() config.debug = CONFIGS.DEBUG - config.bind = ['127.0.0.1:8080'] + config.bind = ['127.0.0.1:28260'] config.accesslog = '-' config.errorlog = '-' diff --git a/core/scripts/webpanel/webpanel_shell.sh b/core/scripts/webpanel/webpanel_shell.sh index 2f8ad23..9d232de 100644 --- a/core/scripts/webpanel/webpanel_shell.sh +++ b/core/scripts/webpanel/webpanel_shell.sh @@ -83,14 +83,14 @@ $DOMAIN:$PORT { # We don't strip the ROOT_PATH('/$ROOT_PATH/') from the request # uri strip_prefix /$ROOT_PATH - # We are proxying all requests under the ROOT_PATH to FastAPI at 127.0.0.1:8080 + # We are proxying all requests under the ROOT_PATH to FastAPI at 127.0.0.1:28260 # FastAPI handles these requests because we set the 'root_path' parameter in the FastAPI instance. - reverse_proxy http://127.0.0.1:8080 + reverse_proxy http://127.0.0.1:28260 } # Any request that doesn't start with the ROOT_PATH('/$ROOT_PATH/') will be blocked and no response will be sent to the client @blocked { - not path /fd31b4edc70619d5d39edf3c2da97e2c/* + not path /$ROOT_PATH/* } # Abort the request, effectively dropping the connection without a response for invalid paths @@ -181,7 +181,7 @@ start_service() { # Check if the web panel is running if systemctl is-active --quiet hysteria-webpanel.service; then - echo -e "${green}Hysteria web panel setup completed. The web panel is running locally on: http://127.0.0.1:8080/${NC}" + echo -e "${green}Hysteria web panel setup completed. The web panel is running locally on: http://127.0.0.1:28260/${NC}" else echo -e "${red}Error: Hysteria web panel service failed to start.${NC}" return 1 diff --git a/install.sh b/install.sh index f95bacf..5bdefb8 100644 --- a/install.sh +++ b/install.sh @@ -31,7 +31,7 @@ fi check_os_version -REQUIRED_PACKAGES=("jq" "qrencode" "curl" "pwgen" "uuid-runtime" "python3" "python3-pip" "python3-venv" "git" "bc" "zip" "cron" "lsof") +REQUIRED_PACKAGES=("jq" "qrencode" "curl" "pwgen" "python3" "python3-pip" "python3-venv" "git" "bc" "zip" "cron" "lsof") MISSING_PACKAGES=() heavy_checkmark=$(printf "\xE2\x9C\x85") diff --git a/upgrade.sh b/upgrade.sh index fe7aa88..c7d9594 100644 --- a/upgrade.sh +++ b/upgrade.sh @@ -13,6 +13,7 @@ FILES=( "/etc/hysteria/core/scripts/singbox/.env" "/etc/hysteria/core/scripts/normalsub/.env" "/etc/hysteria/core/scripts/webpanel/.env" + "/etc/hysteria/core/scripts/webpanel/Caddyfile" ) echo "Backing up and stopping all cron jobs"