diff --git a/VERSION b/VERSION index 0ea3a94..0c62199 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -0.2.0 +0.2.1 diff --git a/core/cli.py b/core/cli.py index 3a1770a..913796b 100644 --- a/core/cli.py +++ b/core/cli.py @@ -100,12 +100,8 @@ def change_hysteria2_port(port: int): @cli.command('get-user') @click.option('--username', '-u', required=True, help='Username for the user to get', type=str) -@click.option('--no-traffic', '-t', is_flag=True, help='Do not display traffic information') -def get_user(username: str, no_traffic: bool): +def get_user(username: str): cmd = ['bash', Command.GET_USER.value, '-u', str(username)] - if no_traffic: - cmd.append('-t') - run_cmd(cmd) @cli.command('add-user') diff --git a/core/scripts/hysteria2/edit_user.sh b/core/scripts/hysteria2/edit_user.sh index f748e55..c5bc81b 100644 --- a/core/scripts/hysteria2/edit_user.sh +++ b/core/scripts/hysteria2/edit_user.sh @@ -67,13 +67,13 @@ convert_blocked_status() { esac } -# Function to get user info +# Function to get user info from users.json get_user_info() { local username=$1 python3 $CLI_PATH get-user -u "$username" -t } -# Function to update user info in JSON +# Function to update user info in users.json update_user_info() { local old_username=$1 local new_username=$2 @@ -96,6 +96,12 @@ update_user_info() { fi echo "User exists." + # Get existing user data + existing_user_data=$(jq --arg username "$old_username" '.[$username]' "$USERS_FILE") + upload_bytes=$(echo "$existing_user_data" | jq -r '.upload_bytes // 0') + download_bytes=$(echo "$existing_user_data" | jq -r '.download_bytes // 0') + status=$(echo "$existing_user_data" | jq -r '.status // "Offline"') + # Debugging output echo "Updating user:" echo "Username: $new_username" @@ -113,6 +119,9 @@ update_user_info() { --argjson expiration_days "${new_expiration_days:-null}" \ --arg account_creation_date "${new_creation_date:-null}" \ --argjson blocked "$(convert_blocked_status "${new_blocked:-false}")" \ + --argjson upload_bytes "$upload_bytes" \ + --argjson download_bytes "$download_bytes" \ + --arg status "$status" \ ' .[$new_username] = .[$old_username] | del(.[$old_username]) | @@ -121,7 +130,10 @@ update_user_info() { .max_download_bytes = ($max_download_bytes // .max_download_bytes) | .expiration_days = ($expiration_days // .expiration_days) | .account_creation_date = ($account_creation_date // .account_creation_date) | - .blocked = $blocked + .blocked = $blocked | + .upload_bytes = $upload_bytes | + .download_bytes = $download_bytes | + .status = $status )' "$USERS_FILE" > tmp.$$.json && mv tmp.$$.json "$USERS_FILE" if [ $? -ne 0 ]; then @@ -129,32 +141,11 @@ update_user_info() { return 1 fi - # Only update traffic_data.json and restart service if the username has changed - if [ "$old_username" != "$new_username" ]; then - # Update username in traffic_data.json - if [ -f "$TRAFFIC_FILE" ]; then - jq --arg old_username "$old_username" \ - --arg new_username "$new_username" \ - ' - .[$new_username] = .[$old_username] | - del(.[$old_username]) - ' "$TRAFFIC_FILE" > tmp.$$.json && mv tmp.$$.json "$TRAFFIC_FILE" + python3 $CLI_PATH restart-hysteria2 - if [ $? -ne 0 ]; then - echo "Error: Failed to update username in '$TRAFFIC_FILE'." - return 1 - fi - else - echo "Warning: '$TRAFFIC_FILE' not found. Skipping traffic data update." - fi - - # Restart Hysteria service after updating user information - python3 $CLI_PATH restart-hysteria2 - - if [ $? -ne 0 ]; then - echo "Error: Failed to restart Hysteria service." - return 1 - fi + if [ $? -ne 0 ]; then + echo "Error: Failed to restart Hysteria service." + exit 1 fi } @@ -203,8 +194,6 @@ edit_user() { # Update user info in JSON file update_user_info "$username" "$new_username" "$new_password" "$new_traffic_limit" "$new_expiration_days" "$new_creation_date" "$new_blocked" - # Restart Hysteria service after updating user information - echo "Restarting Hysteria service..." python3 $CLI_PATH restart-hysteria2 if [ $? -ne 0 ]; then diff --git a/core/scripts/hysteria2/get_user.sh b/core/scripts/hysteria2/get_user.sh index 6d6c5bd..93fee68 100644 --- a/core/scripts/hysteria2/get_user.sh +++ b/core/scripts/hysteria2/get_user.sh @@ -2,25 +2,20 @@ source /etc/hysteria/core/scripts/path.sh -SHOW_TRAFFIC=true - -while getopts ":u:t" opt; do +while getopts ":u:" opt; do case ${opt} in u ) USERNAME=$OPTARG ;; - t ) - SHOW_TRAFFIC=false - ;; \? ) - echo "Usage: $0 -u [-t]" + echo "Usage: $0 -u " exit 1 ;; esac done if [ -z "$USERNAME" ]; then - echo "Usage: $0 -u [-t]" + echo "Usage: $0 -u " exit 1 fi @@ -38,19 +33,12 @@ fi echo "$USER_INFO" | jq . -if [ "$SHOW_TRAFFIC" = true ]; then - if [ ! -f "$TRAFFIC_FILE" ]; then - echo "No traffic data file found at $TRAFFIC_FILE. User might not have connected yet." - exit 0 - fi +UPLOAD_BYTES=$(echo "$USER_INFO" | jq -r '.upload_bytes // "No upload data available"') +DOWNLOAD_BYTES=$(echo "$USER_INFO" | jq -r '.download_bytes // "No download data available"') +STATUS=$(echo "$USER_INFO" | jq -r '.status // "Status unavailable"') - TRAFFIC_INFO=$(jq -r --arg username "$USERNAME" '.[$username] // empty' "$TRAFFIC_FILE") - - if [ -z "$TRAFFIC_INFO" ]; then - echo "No traffic data found for user '$USERNAME' in $TRAFFIC_FILE. User might not have connected yet." - else - echo "$TRAFFIC_INFO" | jq . - fi -fi +echo "Upload Bytes: $UPLOAD_BYTES" +echo "Download Bytes: $DOWNLOAD_BYTES" +echo "Status: $STATUS" exit 0 diff --git a/core/scripts/hysteria2/kick.sh b/core/scripts/hysteria2/kick.sh index be6f3df..a28e0eb 100644 --- a/core/scripts/hysteria2/kick.sh +++ b/core/scripts/hysteria2/kick.sh @@ -15,7 +15,7 @@ for USERNAME in $(jq -r 'keys[]' "$USERS_FILE"); do MAX_DOWNLOAD_BYTES=$(jq -r --arg user "$USERNAME" '.[$user].max_download_bytes' "$USERS_FILE") EXPIRATION_DAYS=$(jq -r --arg user "$USERNAME" '.[$user].expiration_days' "$USERS_FILE") ACCOUNT_CREATION_DATE=$(jq -r --arg user "$USERNAME" '.[$user].account_creation_date' "$USERS_FILE") - CURRENT_DOWNLOAD_BYTES=$(jq -r --arg user "$USERNAME" '.[$user].download_bytes' "$TRAFFIC_FILE") + CURRENT_DOWNLOAD_BYTES=$(jq -r --arg user "$USERNAME" '.[$user].download_bytes' "$USERS_FILE") BLOCKED=$(jq -r --arg user "$USERNAME" '.[$user].blocked' "$USERS_FILE") CURRENT_DATE=$(date +%s) @@ -25,4 +25,4 @@ for USERNAME in $(jq -r 'keys[]' "$USERS_FILE"); do jq --arg user "$USERNAME" '.[$user].blocked = true' "$USERS_FILE" > temp.json && mv temp.json "$USERS_FILE" kick_user "$USERNAME" "$SECRET" fi -done \ No newline at end of file +done diff --git a/core/scripts/hysteria2/remove_user.sh b/core/scripts/hysteria2/remove_user.sh index 1759032..a5e1624 100644 --- a/core/scripts/hysteria2/remove_user.sh +++ b/core/scripts/hysteria2/remove_user.sh @@ -1,29 +1,21 @@ #!/bin/bash -# Source the path.sh script to load the necessary variables source /etc/hysteria/core/scripts/path.sh source /etc/hysteria/core/scripts/utils.sh define_colors -# Function to remove a user from the configuration remove_user() { if [ $# -ne 1 ]; then echo "Usage: $0 " exit 1 fi - username=$1 + local username=$1 if [ -f "$USERS_FILE" ]; then - # Check if the username exists in the users.json file if jq -e "has(\"$username\")" "$USERS_FILE" > /dev/null; then jq --arg username "$username" 'del(.[$username])' "$USERS_FILE" > "${USERS_FILE}.temp" && mv "${USERS_FILE}.temp" "$USERS_FILE" - if [ -f "$TRAFFIC_FILE" ]; then - jq --arg username "$username" 'del(.[$username])' "$TRAFFIC_FILE" > "${TRAFFIC_FILE}.temp" && mv "${TRAFFIC_FILE}.temp" "$TRAFFIC_FILE" - fi - - python3 "$CLI_PATH" restart-hysteria2 > /dev/null 2>&1 echo "User $username removed successfully." else echo -e "${red}Error:${NC} User $username not found." @@ -33,5 +25,4 @@ remove_user() { fi } -# Call the function with the provided username argument remove_user "$1" diff --git a/core/scripts/hysteria2/reset_user.sh b/core/scripts/hysteria2/reset_user.sh index 09c0ea7..edeee1f 100644 --- a/core/scripts/hysteria2/reset_user.sh +++ b/core/scripts/hysteria2/reset_user.sh @@ -1,6 +1,6 @@ #!/bin/bash -source /etc/hysteria/core/scripts/utils.sh +# Source required scripts source /etc/hysteria/core/scripts/path.sh reset_user() { @@ -21,8 +21,10 @@ reset_user() { jq --arg username "$username" \ --arg today "$today" \ ' - .[$username].account_creation_date = $today | - .[$username].blocked = false + .[$username].upload_bytes = 0 | + .[$username].download_bytes = 0 | + .[$username].status = "Offline" | + .[$username].account_creation_date = $today ' "$USERS_FILE" > tmp.$$.json && mv tmp.$$.json "$USERS_FILE" if [ $? -ne 0 ]; then @@ -30,25 +32,10 @@ reset_user() { return 1 fi - if [ ! -f "$TRAFFIC_FILE" ]; then - echo "Warning: File '$TRAFFIC_FILE' not found. Skipping traffic data reset." - else - jq --arg username "$username" \ - ' - .[$username].upload_bytes = 0 | - .[$username].download_bytes = 0 - ' "$TRAFFIC_FILE" > tmp.$$.json && mv tmp.$$.json "$TRAFFIC_FILE" - - if [ $? -ne 0 ]; then - echo "Error: Failed to reset traffic data for user '$username' in '$TRAFFIC_FILE'." - return 1 - fi - fi - echo "User '$username' has been reset successfully." } -if [ $# -eq 0 ]; then +if [ $# -ne 1 ]; then echo "Usage: $0 " exit 1 fi diff --git a/core/scripts/hysteria2/server_info.sh b/core/scripts/hysteria2/server_info.sh index 4eeb9bd..072002c 100644 --- a/core/scripts/hysteria2/server_info.sh +++ b/core/scripts/hysteria2/server_info.sh @@ -50,7 +50,7 @@ echo "Online Users: $online_user_count" echo echo "Total Traffic: " -if [ -f "$TRAFFIC_FILE" ]; then +if [ -f "$USERS_FILE" ]; then total_upload=0 total_download=0 @@ -59,7 +59,7 @@ if [ -f "$TRAFFIC_FILE" ]; then download=$(echo $line | jq -r '.download_bytes') total_upload=$(echo "$total_upload + $upload" | bc) total_download=$(echo "$total_download + $download" | bc) - done <<< "$(jq -c '.[]' $TRAFFIC_FILE)" + done <<< "$(jq -c '.[]' $USERS_FILE)" total_upload_human=$(convert_bytes $total_upload) total_download_human=$(convert_bytes $total_download) diff --git a/core/scripts/hysteria2/user.sh b/core/scripts/hysteria2/user.sh index f5e5ad0..95c5a88 100644 --- a/core/scripts/hysteria2/user.sh +++ b/core/scripts/hysteria2/user.sh @@ -4,30 +4,25 @@ ADDR="$1" AUTH="$2" TX="$3" -# Source the path.sh script to load variables source /etc/hysteria/core/scripts/path.sh -# Extract username and password from AUTH IFS=':' read -r USERNAME PASSWORD <<< "$AUTH" -# Retrieve stored user data STORED_PASSWORD=$(jq -r --arg user "$USERNAME" '.[$user].password' "$USERS_FILE") MAX_DOWNLOAD_BYTES=$(jq -r --arg user "$USERNAME" '.[$user].max_download_bytes' "$USERS_FILE") EXPIRATION_DAYS=$(jq -r --arg user "$USERNAME" '.[$user].expiration_days' "$USERS_FILE") ACCOUNT_CREATION_DATE=$(jq -r --arg user "$USERNAME" '.[$user].account_creation_date' "$USERS_FILE") BLOCKED=$(jq -r --arg user "$USERNAME" '.[$user].blocked' "$USERS_FILE") +CURRENT_DOWNLOAD_BYTES=$(jq -r --arg user "$USERNAME" '.[$user].download_bytes' "$USERS_FILE") -# Check if the user is blocked if [ "$BLOCKED" == "true" ]; then exit 1 fi -# Check if the provided password matches the stored password if [ "$STORED_PASSWORD" != "$PASSWORD" ]; then exit 1 fi -# Check if the user's account has expired CURRENT_DATE=$(date +%s) EXPIRATION_DATE=$(date -d "$ACCOUNT_CREATION_DATE + $EXPIRATION_DAYS days" +%s) @@ -36,9 +31,6 @@ if [ "$CURRENT_DATE" -ge "$EXPIRATION_DATE" ]; then exit 1 fi -# Check if the user's download limit has been exceeded -CURRENT_DOWNLOAD_BYTES=$(jq -r --arg user "$USERNAME" '.[$user].download_bytes' "$TRAFFIC_FILE") - if [ "$CURRENT_DOWNLOAD_BYTES" -ge "$MAX_DOWNLOAD_BYTES" ]; then SECRET=$(jq -r '.trafficStats.secret' "$CONFIG_FILE") KICK_ENDPOINT="http://127.0.0.1:25413/kick" @@ -48,6 +40,5 @@ if [ "$CURRENT_DOWNLOAD_BYTES" -ge "$MAX_DOWNLOAD_BYTES" ]; then exit 1 fi -# If all checks pass, print the username and exit successfully echo "$USERNAME" exit 0 diff --git a/core/scripts/telegrambot/tbot.py b/core/scripts/telegrambot/tbot.py index 5b32783..a6df020 100644 --- a/core/scripts/telegrambot/tbot.py +++ b/core/scripts/telegrambot/tbot.py @@ -127,29 +127,26 @@ def process_show_user(message): command = f"python3 {CLI_PATH} get-user -u {actual_username}" user_result = run_cli_command(command) - - user_json_match = re.search(r'(\{.*?\})\n?(\{.*?\})?', user_result, re.DOTALL) - - if not user_json_match: - bot.reply_to(message, "Failed to parse user details. The command output format may be incorrect.") - return - - user_json = user_json_match.group(1) - traffic_data_section = user_json_match.group(2) try: - user_details = json.loads(user_json) + user_details = json.loads(user_result) - if traffic_data_section: - traffic_data = json.loads(traffic_data_section) + upload_bytes = user_details.get('upload_bytes') + download_bytes = user_details.get('download_bytes') + status = user_details.get('status', 'Unknown') + + if upload_bytes is None or download_bytes is None: + traffic_message = "**Traffic Data:**\nUser not active or no traffic data available." + else: + upload_gb = upload_bytes / (1024 ** 3) # Convert bytes to GB + download_gb = download_bytes / (1024 ** 3) # Convert bytes to GB + traffic_message = ( f"**Traffic Data:**\n" - f"Upload: {traffic_data.get('upload_bytes', 0) / (1024 ** 2):.2f} MB\n" - f"Download: {traffic_data.get('download_bytes', 0) / (1024 ** 2):.2f} MB\n" - f"Status: {traffic_data.get('status', 'Unknown')}" + f"Upload: {upload_gb:.2f} GB\n" + f"Download: {download_gb:.2f} GB\n" + f"Status: {status}" ) - else: - traffic_message = "**Traffic Data:**\nNo traffic data available. The user might not have connected yet." except json.JSONDecodeError: bot.reply_to(message, "Failed to parse JSON data. The command output may be malformed.") return diff --git a/core/traffic.py b/core/traffic.py index a623ba5..17735ab 100644 --- a/core/traffic.py +++ b/core/traffic.py @@ -5,7 +5,7 @@ import os # Define static variables for paths and URLs CONFIG_FILE = '/etc/hysteria/config.json' -TRAFFIC_FILE = '/etc/hysteria/traffic_data.json' +USERS_FILE = '/etc/hysteria/users.json' TRAFFIC_API_URL = 'http://127.0.0.1:25413/traffic?clear=1' ONLINE_API_URL = 'http://127.0.0.1:25413/online' @@ -47,40 +47,38 @@ def traffic_status(): response_dict = json.loads(response) online_dict = json.loads(online_response) - traffic_data = {} - - for user in response_dict.keys(): - tx_bytes = response_dict[user].get('tx', 0) - rx_bytes = response_dict[user].get('rx', 0) - online = online_dict.get(user, 0) - - traffic_data[user] = { - "upload_bytes": tx_bytes, - "download_bytes": rx_bytes, - "status": "Online" if online == 1 else "Offline" - } - - existing_data = {} - if os.path.exists(TRAFFIC_FILE): + # Load the current users.json data + users_data = {} + if os.path.exists(USERS_FILE): try: - with open(TRAFFIC_FILE, 'r') as json_file: - existing_data = json.load(json_file) + with open(USERS_FILE, 'r') as users_file: + users_data = json.load(users_file) except json.JSONDecodeError: - print("Error: Failed to parse existing traffic data JSON file.") + print("Error: Failed to parse existing users data JSON file.") return - for user, data in traffic_data.items(): - if user in existing_data: - existing_data[user]["upload_bytes"] += data["upload_bytes"] - existing_data[user]["download_bytes"] += data["download_bytes"] - existing_data[user]["status"] = data["status"] + # Update users.json with traffic data + for user, traffic_info in response_dict.items(): + tx_bytes = traffic_info.get('tx', 0) + rx_bytes = traffic_info.get('rx', 0) + online_status = online_dict.get(user, 0) + + if user in users_data: + users_data[user]["upload_bytes"] = users_data[user].get("upload_bytes", 0) + tx_bytes + users_data[user]["download_bytes"] = users_data[user].get("download_bytes", 0) + rx_bytes + users_data[user]["status"] = "Online" if online_status == 1 else "Offline" else: - existing_data[user] = data + users_data[user] = { + "upload_bytes": tx_bytes, + "download_bytes": rx_bytes, + "status": "Online" if online_status == 1 else "Offline" + } - with open(TRAFFIC_FILE, 'w') as json_file: - json.dump(existing_data, json_file, indent=4) + # Save the updated data back to users.json + with open(USERS_FILE, 'w') as users_file: + json.dump(users_data, users_file, indent=4) - display_traffic_data(existing_data, green, cyan, NC) + display_traffic_data(users_data, green, cyan, NC) def display_traffic_data(data, green, cyan, NC): if not data: @@ -93,9 +91,9 @@ def display_traffic_data(data, green, cyan, NC): print("-------------------------------------------------") for user, entry in data.items(): - upload_bytes = entry["upload_bytes"] - download_bytes = entry["download_bytes"] - status = entry["status"] + upload_bytes = entry.get("upload_bytes", 0) + download_bytes = entry.get("download_bytes", 0) + status = entry.get("status", "Offline") formatted_tx = format_bytes(upload_bytes) formatted_rx = format_bytes(download_bytes) @@ -114,3 +112,6 @@ def format_bytes(bytes): return f"{bytes / 1073741824:.2f}GB" else: return f"{bytes / 1099511627776:.2f}TB" + +if __name__ == "__main__": + traffic_status() diff --git a/menu.sh b/menu.sh index 0fd4114..9595e44 100644 --- a/menu.sh +++ b/menu.sh @@ -263,7 +263,12 @@ warp_configure_handler() { python3 $CLI_PATH configure-warp --warp-option "warp plus" --warp-key "$warp_key" ;; 6) python3 $CLI_PATH configure-warp --warp-option "warp" ;; - 7) cd /etc/warp/ && wgcf status ;; + 7) + ip=$(curl -s --interface wgcf --connect-timeout 0.5 http://v4.ident.me) + cd /etc/warp/ && wgcf status + echo + echo -e "${yellow}Warp IP :${NC} ${cyan}$ip ${NC}" ;; + 8) old_ip=$(curl -s --interface wgcf --connect-timeout 0.5 http://v4.ident.me) echo "Current IP address: $old_ip" diff --git a/upgrade.sh b/upgrade.sh index f4f3161..1116fef 100644 --- a/upgrade.sh +++ b/upgrade.sh @@ -1,4 +1,5 @@ #!/bin/bash + cd /root/ TEMP_DIR=$(mktemp -d) @@ -34,6 +35,16 @@ for FILE in "${FILES[@]}"; do cp "$TEMP_DIR/$FILE" "$FILE" done +echo "Merging traffic data into users.json" + +if [ -f /etc/hysteria/traffic_data.json ]; then + jq -s '.[0] * .[1]' /etc/hysteria/users.json /etc/hysteria/traffic_data.json > /etc/hysteria/users_temp.json + mv /etc/hysteria/users_temp.json /etc/hysteria/users.json + # rm /etc/hysteria/traffic_data.json +else + echo "No traffic_data.json found to merge." +fi + echo "Setting ownership and permissions" chown hysteria:hysteria /etc/hysteria/ca.key /etc/hysteria/ca.crt chmod 640 /etc/hysteria/ca.key /etc/hysteria/ca.crt