diff --git a/changelog b/changelog index 076a875..afe40b4 100644 --- a/changelog +++ b/changelog @@ -1,2 +1,6 @@ 1. Fix: Changed geo category 2. Reject(malware, phishing, cryptominers) +3. Add: GeoCountry(Iran, China, and Russia) +4. Add: Geo Update flag --country option(cli) +5. Add: CPU monitoring module(Telegram-Bot) +6. Add: Search users by the `blocked` status(Telegram-Bot) diff --git a/core/cli.py b/core/cli.py index bb27e28..adf918e 100644 --- a/core/cli.py +++ b/core/cli.py @@ -289,10 +289,14 @@ def ip_address(edit, ipv4, ipv6): run_cmd(['bash', Command.IP_ADD.value, 'add']) @cli.command('update-geo') -def cli_update_geo(): +@click.option('--country', '-c', + type=click.Choice(['iran', 'china', 'russia'], case_sensitive=False), + default='iran', + help='Select country for geo files (default: iran)') +def cli_update_geo(country): script_path = Command.UPDATE_GEO.value try: - subprocess.run(['python3', script_path], check=True) + subprocess.run(['python3', script_path, country.lower()], check=True) except subprocess.CalledProcessError as e: print(f"Failed to update geo files: {e}") except FileNotFoundError: diff --git a/core/scripts/hysteria2/update_geo.py b/core/scripts/hysteria2/update_geo.py index 3b227c3..ba25ff3 100644 --- a/core/scripts/hysteria2/update_geo.py +++ b/core/scripts/hysteria2/update_geo.py @@ -1,46 +1,70 @@ #!/usr/bin/env python3 import os import subprocess +from enum import Enum +import sys +import requests + + +class GeoCountry(Enum): + IRAN = { + 'geosite': 'https://github.com/chocolate4u/Iran-v2ray-rules/releases/latest/download/geosite.dat', + 'geoip': 'https://github.com/chocolate4u/Iran-v2ray-rules/releases/latest/download/geoip.dat' + } + CHINA = { + 'geosite': 'https://github.com/Loyalsoldier/v2ray-rules-dat/releases/latest/download/geosite.dat', + 'geoip': 'https://github.com/Loyalsoldier/v2ray-rules-dat/releases/latest/download/geoip.dat' + } + RUSSIA = { + 'geosite': 'https://github.com/runetfreedom/russia-v2ray-rules-dat/releases/latest/download/geosite.dat', + 'geoip': 'https://github.com/runetfreedom/russia-v2ray-rules-dat/releases/latest/download/geoip.dat' + } GEOSITE_PATH = "/etc/hysteria/geosite.dat" GEOIP_PATH = "/etc/hysteria/geoip.dat" -GEOSITE_URL = "https://raw.githubusercontent.com/Chocolate4U/Iran-v2ray-rules/release/geosite.dat" -GEOIP_URL = "https://raw.githubusercontent.com/Chocolate4U/Iran-v2ray-rules/release/geoip.dat" - def remove_file(file_path): - if os.path.exists(file_path): - os.remove(file_path) - print(f"Removed existing file: {file_path}") - - -def download_file(url, destination): try: - subprocess.run( - ["wget", "-O", destination, url], - stdout=subprocess.DEVNULL, - stderr=subprocess.DEVNULL, - check=True - ) - print(f"Downloaded {url} to {destination}") - except subprocess.CalledProcessError: - print(f"Failed to download {url}") + if os.path.exists(file_path): + os.remove(file_path) + print(f"Removed existing file: {file_path}") + except Exception as e: + print(f"Error removing file {file_path}: {e}") - -def update_geo_files(): +def download_file(url, destination, chunk_size=8192): try: - print("Starting geo files update...") + destination_dir = os.path.dirname(destination) + if destination_dir and not os.path.exists(destination_dir): + os.makedirs(destination_dir) + response = requests.get(url, stream=True) + response.raise_for_status() + + with open(destination, "wb") as file: + for chunk in response.iter_content(chunk_size=chunk_size): + file.write(chunk) + + print(f"File successfully downloaded to: {destination}") + + except requests.exceptions.RequestException as e: + print(f"Error: Failed to download the file from '{url}'.\n{e}") + except IOError as e: + print(f"Error: Failed to save the file to '{destination}'.\n{e}") + +def update_geo_files(country='iran'): + try: + print(f"Starting geo files update for {country.upper()}...") + country_enum = GeoCountry[country.upper()] remove_file(GEOSITE_PATH) remove_file(GEOIP_PATH) - download_file(GEOSITE_URL, GEOSITE_PATH) - download_file(GEOIP_URL, GEOIP_PATH) - + download_file(country_enum.value['geosite'], GEOSITE_PATH) + download_file(country_enum.value['geoip'], GEOIP_PATH) print("Geo files update completed successfully.") - + except KeyError: + print(f"Invalid country selection. Available options: {', '.join([c.name.lower() for c in GeoCountry])}") except Exception as e: print(f"An error occurred during the update process: {e}") - if __name__ == "__main__": - update_geo_files() + country = sys.argv[1] if len(sys.argv) > 1 else 'iran' + update_geo_files(country) diff --git a/core/scripts/telegrambot/tbot.py b/core/scripts/telegrambot/tbot.py index 7c6f472..6c06904 100644 --- a/core/scripts/telegrambot/tbot.py +++ b/core/scripts/telegrambot/tbot.py @@ -7,6 +7,9 @@ from utils.deleteuser import * from utils.edituser import * from utils.search import * from utils.serverinfo import * +from utils.cpu import * +import threading +import time @bot.message_handler(commands=['start']) def send_welcome(message): @@ -16,5 +19,12 @@ def send_welcome(message): else: bot.reply_to(message, "Unauthorized access. You do not have permission to use this bot.") +def monitoring_thread(): + while True: + monitor_system_resources() + time.sleep(60) + if __name__ == '__main__': + monitor_thread = threading.Thread(target=monitoring_thread, daemon=True) + monitor_thread.start() bot.polling(none_stop=True) diff --git a/core/scripts/telegrambot/utils/cpu.py b/core/scripts/telegrambot/utils/cpu.py new file mode 100644 index 0000000..a2baed2 --- /dev/null +++ b/core/scripts/telegrambot/utils/cpu.py @@ -0,0 +1,64 @@ +import psutil +import time +from utils.command import * + + +def get_system_usage(): + cpu_usage = psutil.cpu_percent(interval=1) + ram = psutil.virtual_memory() + ram_usage = ram.percent + return cpu_usage, ram_usage + +def format_alert_message(cpu_usage, ram_usage): + return ( + "🚨ALERT🚨\n" + "High CPU and RAM usage detected ⚠️\n\n" + f"πŸ“ˆ CPU: {cpu_usage:.1f}%\n" + f"πŸ“‹ RAM: {ram_usage:.1f}%" + ) + +def monitor_system_resources(): + # Thresholds + CPU_THRESHOLD = 90.0 + RAM_THRESHOLD = 90.0 + CONFIRMATION_DELAY = 60 # seconds + + try: + cpu_usage, ram_usage = get_system_usage() + + if cpu_usage > CPU_THRESHOLD and ram_usage > RAM_THRESHOLD: + time.sleep(CONFIRMATION_DELAY) + cpu_usage, ram_usage = get_system_usage() + + if cpu_usage > CPU_THRESHOLD and ram_usage > RAM_THRESHOLD: + alert_message = format_alert_message(cpu_usage, ram_usage) + + for admin_id in ADMIN_USER_IDS: + try: + bot.send_message(admin_id, alert_message) + except Exception as e: + print(f"Failed to send alert to admin {admin_id}: {str(e)}") + + return True + + except Exception as e: + print(f"Error monitoring system resources: {str(e)}") + + return False + +@bot.message_handler(commands=['system']) +def check_system(message): + if not is_admin(message.from_user.id): + bot.reply_to(message, "Unauthorized access. You do not have permission to use this command.") + return + + try: + cpu_usage, ram_usage = get_system_usage() + response = ( + "πŸ“Š System Resource Usage πŸ“Š\n\n" + f"πŸ“ˆ CPU Usage: {cpu_usage:.1f}%\n" + f"πŸ“‹ RAM Usage: {ram_usage:.1f}%" + ) + bot.reply_to(message, response) + except Exception as e: + bot.reply_to(message, f"Error checking system resources: {str(e)}") diff --git a/core/scripts/telegrambot/utils/search.py b/core/scripts/telegrambot/utils/search.py index 494bdf2..31821e0 100644 --- a/core/scripts/telegrambot/utils/search.py +++ b/core/scripts/telegrambot/utils/search.py @@ -1,7 +1,6 @@ from telebot import types from utils.command import * - @bot.inline_handler(lambda query: is_admin(query.from_user.id)) def handle_inline_query(query): command = f"python3 {CLI_PATH} list-users" @@ -14,21 +13,40 @@ def handle_inline_query(query): query_text = query.query.lower() results = [] - for username, details in users.items(): - if query_text in username.lower(): - title = f"{username}" - description = f"Traffic Limit: {details['max_download_bytes'] / (1024 ** 3):.2f} GB, Expiration Days: {details['expiration_days']}" - results.append(types.InlineQueryResultArticle( - id=username, - title=title, - description=description, - input_message_content=types.InputTextMessageContent( - message_text=f"Name: {username}\n" - f"Traffic limit: {details['max_download_bytes'] / (1024 ** 3):.2f} GB\n" - f"Days: {details['expiration_days']}\n" - f"Account Creation: {details['account_creation_date']}\n" - f"Blocked: {details['blocked']}" - ) - )) - bot.answer_inline_query(query.id, results, cache_time=0) \ No newline at end of file + if query_text == "block": + for username, details in users.items(): + if details.get('blocked', False): + title = f"{username} (Blocked)" + description = f"Traffic Limit: {details['max_download_bytes'] / (1024 ** 3):.2f} GB, Expiration Days: {details['expiration_days']}" + results.append(types.InlineQueryResultArticle( + id=username, + title=title, + description=description, + input_message_content=types.InputTextMessageContent( + message_text=f"Name: {username}\n" + f"Traffic limit: {details['max_download_bytes'] / (1024 ** 3):.2f} GB\n" + f"Days: {details['expiration_days']}\n" + f"Account Creation: {details['account_creation_date']}\n" + f"Blocked: {details['blocked']}" + ) + )) + else: + for username, details in users.items(): + if query_text in username.lower(): + title = f"{username}" + description = f"Traffic Limit: {details['max_download_bytes'] / (1024 ** 3):.2f} GB, Expiration Days: {details['expiration_days']}" + results.append(types.InlineQueryResultArticle( + id=username, + title=title, + description=description, + input_message_content=types.InputTextMessageContent( + message_text=f"Name: {username}\n" + f"Traffic limit: {details['max_download_bytes'] / (1024 ** 3):.2f} GB\n" + f"Days: {details['expiration_days']}\n" + f"Account Creation: {details['account_creation_date']}\n" + f"Blocked: {details['blocked']}" + ) + )) + + bot.answer_inline_query(query.id, results, cache_time=0) diff --git a/menu.sh b/menu.sh index 339ccf1..51dbc19 100644 --- a/menu.sh +++ b/menu.sh @@ -589,6 +589,57 @@ obfs_handler() { 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 +} + # Function to display the main menu display_main_menu() { clear @@ -737,7 +788,7 @@ advance_menu() { 9) hysteria2_change_sni_handler ;; 10) obfs_handler ;; 11) edit_ips ;; - 12) python3 $CLI_PATH update-geo ;; + 12) geo_update_handler ;; 13) python3 $CLI_PATH restart-hysteria2 ;; 14) python3 $CLI_PATH update-hysteria2 ;; 15) python3 $CLI_PATH uninstall-hysteria2 ;; diff --git a/requirements.txt b/requirements.txt index 346c6a5..836d506 100644 --- a/requirements.txt +++ b/requirements.txt @@ -4,3 +4,4 @@ python-dotenv==1.0.1 requests==2.32.3 aiohttp==3.10.5 click==8.1.7 +psutil==6.1.1