@ -1,2 +1,6 @@
|
|||||||
1. Fix: Changed geo category
|
1. Fix: Changed geo category
|
||||||
2. Reject(malware, phishing, cryptominers)
|
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)
|
||||||
|
|||||||
@ -289,10 +289,14 @@ def ip_address(edit, ipv4, ipv6):
|
|||||||
run_cmd(['bash', Command.IP_ADD.value, 'add'])
|
run_cmd(['bash', Command.IP_ADD.value, 'add'])
|
||||||
|
|
||||||
@cli.command('update-geo')
|
@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
|
script_path = Command.UPDATE_GEO.value
|
||||||
try:
|
try:
|
||||||
subprocess.run(['python3', script_path], check=True)
|
subprocess.run(['python3', script_path, country.lower()], check=True)
|
||||||
except subprocess.CalledProcessError as e:
|
except subprocess.CalledProcessError as e:
|
||||||
print(f"Failed to update geo files: {e}")
|
print(f"Failed to update geo files: {e}")
|
||||||
except FileNotFoundError:
|
except FileNotFoundError:
|
||||||
|
|||||||
@ -1,46 +1,70 @@
|
|||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
import os
|
import os
|
||||||
import subprocess
|
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"
|
GEOSITE_PATH = "/etc/hysteria/geosite.dat"
|
||||||
GEOIP_PATH = "/etc/hysteria/geoip.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):
|
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:
|
try:
|
||||||
subprocess.run(
|
if os.path.exists(file_path):
|
||||||
["wget", "-O", destination, url],
|
os.remove(file_path)
|
||||||
stdout=subprocess.DEVNULL,
|
print(f"Removed existing file: {file_path}")
|
||||||
stderr=subprocess.DEVNULL,
|
except Exception as e:
|
||||||
check=True
|
print(f"Error removing file {file_path}: {e}")
|
||||||
)
|
|
||||||
print(f"Downloaded {url} to {destination}")
|
|
||||||
except subprocess.CalledProcessError:
|
|
||||||
print(f"Failed to download {url}")
|
|
||||||
|
|
||||||
|
def download_file(url, destination, chunk_size=8192):
|
||||||
def update_geo_files():
|
|
||||||
try:
|
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(GEOSITE_PATH)
|
||||||
remove_file(GEOIP_PATH)
|
remove_file(GEOIP_PATH)
|
||||||
download_file(GEOSITE_URL, GEOSITE_PATH)
|
download_file(country_enum.value['geosite'], GEOSITE_PATH)
|
||||||
download_file(GEOIP_URL, GEOIP_PATH)
|
download_file(country_enum.value['geoip'], GEOIP_PATH)
|
||||||
|
|
||||||
print("Geo files update completed successfully.")
|
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:
|
except Exception as e:
|
||||||
print(f"An error occurred during the update process: {e}")
|
print(f"An error occurred during the update process: {e}")
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
update_geo_files()
|
country = sys.argv[1] if len(sys.argv) > 1 else 'iran'
|
||||||
|
update_geo_files(country)
|
||||||
|
|||||||
@ -7,6 +7,9 @@ from utils.deleteuser import *
|
|||||||
from utils.edituser import *
|
from utils.edituser import *
|
||||||
from utils.search import *
|
from utils.search import *
|
||||||
from utils.serverinfo import *
|
from utils.serverinfo import *
|
||||||
|
from utils.cpu import *
|
||||||
|
import threading
|
||||||
|
import time
|
||||||
|
|
||||||
@bot.message_handler(commands=['start'])
|
@bot.message_handler(commands=['start'])
|
||||||
def send_welcome(message):
|
def send_welcome(message):
|
||||||
@ -16,5 +19,12 @@ def send_welcome(message):
|
|||||||
else:
|
else:
|
||||||
bot.reply_to(message, "Unauthorized access. You do not have permission to use this bot.")
|
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__':
|
if __name__ == '__main__':
|
||||||
|
monitor_thread = threading.Thread(target=monitoring_thread, daemon=True)
|
||||||
|
monitor_thread.start()
|
||||||
bot.polling(none_stop=True)
|
bot.polling(none_stop=True)
|
||||||
|
|||||||
64
core/scripts/telegrambot/utils/cpu.py
Normal file
64
core/scripts/telegrambot/utils/cpu.py
Normal file
@ -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)}")
|
||||||
@ -1,7 +1,6 @@
|
|||||||
from telebot import types
|
from telebot import types
|
||||||
from utils.command import *
|
from utils.command import *
|
||||||
|
|
||||||
|
|
||||||
@bot.inline_handler(lambda query: is_admin(query.from_user.id))
|
@bot.inline_handler(lambda query: is_admin(query.from_user.id))
|
||||||
def handle_inline_query(query):
|
def handle_inline_query(query):
|
||||||
command = f"python3 {CLI_PATH} list-users"
|
command = f"python3 {CLI_PATH} list-users"
|
||||||
@ -14,21 +13,40 @@ def handle_inline_query(query):
|
|||||||
|
|
||||||
query_text = query.query.lower()
|
query_text = query.query.lower()
|
||||||
results = []
|
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)
|
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)
|
||||||
|
|||||||
53
menu.sh
53
menu.sh
@ -589,6 +589,57 @@ obfs_handler() {
|
|||||||
done
|
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
|
# Function to display the main menu
|
||||||
display_main_menu() {
|
display_main_menu() {
|
||||||
clear
|
clear
|
||||||
@ -737,7 +788,7 @@ advance_menu() {
|
|||||||
9) hysteria2_change_sni_handler ;;
|
9) hysteria2_change_sni_handler ;;
|
||||||
10) obfs_handler ;;
|
10) obfs_handler ;;
|
||||||
11) edit_ips ;;
|
11) edit_ips ;;
|
||||||
12) python3 $CLI_PATH update-geo ;;
|
12) geo_update_handler ;;
|
||||||
13) python3 $CLI_PATH restart-hysteria2 ;;
|
13) python3 $CLI_PATH restart-hysteria2 ;;
|
||||||
14) python3 $CLI_PATH update-hysteria2 ;;
|
14) python3 $CLI_PATH update-hysteria2 ;;
|
||||||
15) python3 $CLI_PATH uninstall-hysteria2 ;;
|
15) python3 $CLI_PATH uninstall-hysteria2 ;;
|
||||||
|
|||||||
@ -4,3 +4,4 @@ python-dotenv==1.0.1
|
|||||||
requests==2.32.3
|
requests==2.32.3
|
||||||
aiohttp==3.10.5
|
aiohttp==3.10.5
|
||||||
click==8.1.7
|
click==8.1.7
|
||||||
|
psutil==6.1.1
|
||||||
|
|||||||
Reference in New Issue
Block a user