shivam commited on
Commit
c90be15
Β·
0 Parent(s):
Files changed (10) hide show
  1. Auto_install.sh +130 -0
  2. Dockerfile +77 -0
  3. README.md +81 -0
  4. addons.txt +5 -0
  5. bot.py +215 -0
  6. config.example +4 -0
  7. reqs.txt +15 -0
  8. requirements.txt +4 -0
  9. server.py +842 -0
  10. start.sh +27 -0
Auto_install.sh ADDED
@@ -0,0 +1,130 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/bin/bash
2
+
3
+ ## Set default commands
4
+ pipCommand="pip"
5
+ pythonCommand="python"
6
+ useBale=0
7
+
8
+ ## Display help for commands
9
+ showHelp() {
10
+ echo -e "Autoinstall usage: $0 [option..]\n
11
+ -b, --bale For install bale api instead of Telegram API \n
12
+ -h, --help This help message\n
13
+ -d, --debug Enable bash debug\n
14
+ -i, --interactive Install requirements for interactive commands\n
15
+ -u, --useful Install useful commands\n
16
+ -3, --python3 Use python3 instead of Python2\n
17
+ "
18
+ exit 0
19
+ }
20
+
21
+ ## Use virtualenv
22
+ useVenv() {
23
+ ## Create virtual environment
24
+ virtualenv -p $pythonCommand venv
25
+ ## Activate virtual environment
26
+ source venv/bin/activate
27
+ }
28
+
29
+
30
+ useBaleAPI() {
31
+ ## Change telegram API URL to Bale API URL
32
+ find ./ -name bot.py -exec sed -i 's/api\.telegram\.org/tapi.bale.ai/mg' {} \;
33
+ }
34
+
35
+
36
+ ## to use interactive commands like htop we need these packages
37
+ installAha() {
38
+ [ -f "/etc/debian_version" ] && apt-get update && apt-get install -y aha && return 0
39
+ (git clone https://github.com/theZiz/aha.git && cd aha && make && make install return 0) || ( echo "cannot install aha, please use -d to debug \nPlease submit an issue here:\n https://github.com/MParvin/TSMB/issues/new" && exit 1)
40
+
41
+ }
42
+
43
+ ## Install useful commands
44
+ installUsefulCMD() {
45
+ echo "Installing htop, please wait a moment..."
46
+ yum install -y htop &> /dev/null || apt install -y htop &> /dev/null
47
+ }
48
+
49
+ configureBot(){
50
+ echo -e "To configure your bot, you must have a Telegram or Bale token\n
51
+ How to create Telegram bot: https://core.telegram.org/bots#3-how-do-i-create-a-bot\n
52
+ How to create Bale bot: https://devbale.ir/quick-start\n"
53
+ read -p "Enter your bot token here:"
54
+
55
+ telegramToken=$REPLY
56
+
57
+ echo -e "Get chat_id and enter here:\n
58
+ To get chat_id do:
59
+ - In telegram:\n start a chat with @id_chatbot
60
+ - In Bale:\n start a chat with chatid_bot
61
+ "
62
+ chatId=$REPLY
63
+ }
64
+
65
+ while :
66
+ do
67
+ case "$1" in
68
+ -b | --bale)
69
+ which virtualenv &> /dev/null || (echo "Cannot use Bale without virtualenv, please run \"pip install virtualenv\" before run this script with -b option" && exit 1)
70
+ useBale = "True"
71
+ break
72
+ ;;
73
+ -h | --help)
74
+ showHelp
75
+ exit 0
76
+ ;;
77
+ -d | --debug)
78
+ set -x
79
+ break
80
+ ;;
81
+ -i | --interactive)
82
+ installAha
83
+ break
84
+ ;;
85
+ -u | --useful)
86
+ installUsefulCMD
87
+ break
88
+ ;;
89
+ -3 | --python3)
90
+ pythonCommand="python3"
91
+ pipCommand="pip3"
92
+ break
93
+ ;;
94
+ *)
95
+ break
96
+ ;;
97
+
98
+ esac
99
+ done
100
+
101
+
102
+ ## Check is python installed
103
+ which $pythonCommand &> /dev/null || (echo "Please install python, and run this script again" && exit 1)
104
+ ## Check is pip installed
105
+ which $pipCommand &> /dev/null || (echo -e "Please install pip, and run this script again\n
106
+ In Debian base system for python2.* use apt-get install python-pip\n
107
+ for python3.* use apt-get install python3-pip" && exit 1)
108
+
109
+ ## Install virtualenv if is not installed
110
+ (which virtualenv &> /dev/null && useVenv) || read -p "Do you want to install virtualenv(y/n)? " -n 1 -r
111
+ ## User accepted
112
+ [[ ! $REPLY =~ ^[yY]$ ]] && $pipCommand install virtualenv --user && useVenv
113
+
114
+ ## Install requirements
115
+ ([ -f requirements.txt ] && $pipCommand install -r requirements.txt) || echo "Could not find requirements.txt, please clone complete this repository from here:\nhttps://github.com/MParvin/TSMB/, \nthen run Autoinstall.sh"
116
+ if [ "$useBale" -eq 1 ]
117
+ then
118
+ useBaleAPI
119
+ fi
120
+
121
+
122
+ read -p "Do you want to configure your bot now(y/n)?"
123
+ if [ $REPLY =~ ^[yY] ]
124
+ then
125
+ configureBot
126
+ else
127
+ echo -e "To use this bot, first change variables in \"config\" file\n
128
+ then executable bot script \"chmod +x bot.py \"
129
+ and run it: \"./bot.py \""
130
+ fi
Dockerfile ADDED
@@ -0,0 +1,77 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ FROM python:3.9.5-buster
2
+
3
+ # Fix apt sources for old Buster release
4
+ RUN sed -i 's|deb.debian.org|archive.debian.org|g' /etc/apt/sources.list && \
5
+ sed -i 's|security.debian.org|archive.debian.org|g' /etc/apt/sources.list && \
6
+ sed -i '/stretch-updates/d' /etc/apt/sources.list && \
7
+ echo 'Acquire::Check-Valid-Until "false";' > /etc/apt/apt.conf.d/99no-check-valid-until
8
+
9
+ # Set timezone
10
+ ENV TZ=Asia/Kolkata
11
+ RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone
12
+
13
+ RUN sed -i 's/main/main contrib non-free/' /etc/apt/sources.list && \
14
+ apt-get update && \
15
+ apt-get install -y --no-install-recommends \
16
+ neofetch \
17
+ git \
18
+ curl \
19
+ wget \
20
+ mediainfo \
21
+ ffmpeg \
22
+ p7zip-full \
23
+ unrar \
24
+ unzip \
25
+ libssl-dev \
26
+ libffi-dev \
27
+ python3-dev && \
28
+ apt-get autoremove --purge -y && \
29
+ rm -rf /var/lib/apt/lists/*
30
+
31
+ # Set working directory
32
+ WORKDIR /Ult
33
+
34
+ # Copy the application code
35
+ COPY . .
36
+
37
+ # --- FIX 1: Connection Speed & Stability ---
38
+ # Installing cryptg speeds up encryption, preventing timeouts.
39
+ # pysocks helps with connection routing.
40
+ RUN pip3 install --no-cache-dir pysocks cryptg
41
+
42
+ RUN if [ -f reqs.txt ]; then pip3 install --no-cache-dir -r reqs.txt; fi
43
+ RUN pip3 install -U pip
44
+ RUN pip3 install -U redis
45
+
46
+ RUN if [ -f addons.txt ]; then pip3 install --no-cache-dir -r addons.txt; fi
47
+ RUN pip3 install --no-cache-dir -r requirements.txt
48
+ RUN if [ -f resources/startup/optional-requirements.txt ]; then pip3 install --no-cache-dir -r resources/startup/optional-requirements.txt; fi || true
49
+
50
+ # --- FIX 2: Resolve Crash (Server.py) ---
51
+ # Downgrade FastAPI to be compatible with Pydantic v1 (which your bot likely uses)
52
+ # This fixes: ImportError: cannot import name 'TypeAdapter' from 'pydantic'
53
+ RUN pip3 install "fastapi<0.100.0" "pydantic<2.0.0" uvicorn
54
+
55
+ # Set appropriate permissions
56
+ RUN chown -R 1000:0 /Ult \
57
+ && chown -R 1000:0 . \
58
+ && chmod 777 . \
59
+ && chmod 777 /usr \
60
+ && chown -R 1000:0 /usr \
61
+ && chmod -R 755 /Ult \
62
+ && chmod +x /Ult/start.sh
63
+
64
+ # Install FFmpeg
65
+ RUN wget https://johnvansickle.com/ffmpeg/builds/ffmpeg-git-amd64-static.tar.xz && \
66
+ wget https://johnvansickle.com/ffmpeg/builds/ffmpeg-git-amd64-static.tar.xz.md5 && \
67
+ md5sum -c ffmpeg-git-amd64-static.tar.xz.md5 && \
68
+ tar xvf ffmpeg-git-amd64-static.tar.xz && \
69
+ mv ffmpeg-git*/ffmpeg ffmpeg-git*/ffprobe /usr/local/bin/ && \
70
+ rm -rf ffmpeg-git* *.tar.xz *.md5
71
+
72
+ # Expose port
73
+ EXPOSE 7860
74
+
75
+ # --- TRICK 3: Auto-delete session + Force IPv4 ---
76
+ # Deletes old sessions AND forces Python to use IPv4 for DNS (helps with connection blocks)
77
+ CMD ["bash", "-c", "echo 'πŸ”„ TRICK: Cleaning sessions...' && find . -name '*.session' -type f -delete && python3 server.py & python3 bot.py"]
README.md ADDED
@@ -0,0 +1,81 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ title: Telegram Remote Command Runner
3
+ emoji: πŸ€–
4
+ colorFrom: blue
5
+ colorTo: gray
6
+ sdk: docker
7
+ pinned: false
8
+ ---
9
+
10
+ # Telegram Server Manager Bot
11
+
12
+ The Telegram Server Manager Bot is a tool that allows you to remotely manage your Raspberry Pi, PC, or server using Telegram. With this bot, you can run commands from anywhere using your smartphone or computer, without needing to log in to your server directly. This can be especially useful if you want to check on your server's status, restart a service, or troubleshoot an issue while you're away from your desk.
13
+
14
+ ## Hugging Face Spaces Deployment
15
+
16
+ This repository is now compatible with Hugging Face Spaces! You can deploy this bot to Hugging Face Spaces for 24/7 availability.
17
+
18
+ ### Features for Hugging Face Spaces:
19
+ - βœ… Runs on Python 3.9.5
20
+ - βœ… Web interface on port 7860
21
+ - βœ… Automatic session cleanup
22
+ - βœ… FastAPI health monitoring
23
+ - βœ… Support for eval command to run Python code
24
+
25
+ ### Deploy to Hugging Face Spaces:
26
+ 1. Fork this repository
27
+ 2. Create a new Space on Hugging Face
28
+ 3. Select "Docker" as the SDK
29
+ 4. Connect your GitHub repository
30
+ 5. Add your Telegram bot token and admin chat ID as Space secrets
31
+ 6. Deploy!
32
+
33
+ ## Prerequisites
34
+
35
+ To use the Telegram Server Manager Bot, you will need the following:
36
+
37
+ * A Telegram account.
38
+ * A Telegram bot token. You can generate this by talking to @BotFather on Telegram.
39
+ * Python 3.x installed on your RaspberryPi, PC, or server.
40
+
41
+
42
+ ## Installation
43
+
44
+ 1. Clone this repository to your RaspberryPi, PC, or server.
45
+
46
+ 2. Install the required dependencies by running `pip install -r requirements.txt` in the terminal.
47
+
48
+ 3. Rename config.example to config and replace YOUR_TOKEN with your Telegram bot token, YOUR_CHAT_ID with your Telegram chat ID, and ADMIN_CID with the chat ID of the admin who is authorized to execute commands.
49
+
50
+ 4. Make the bot.py file executable by running chmod +x bot.py in the terminal.
51
+
52
+ 5. Run the bot by running ./bot.py in the terminal.
53
+
54
+
55
+ ## Usage
56
+
57
+ To use the Telegram Server Manager Bot, simply open Telegram and start a chat with your bot. Only the admin can execute commands, so make sure to add the admin chat ID to the configuration file. You can then run any of the built-in commands or enter any Linux command that you want to run on your RaspberryPi, PC, or server.
58
+
59
+ It also supports the following commands:
60
+
61
+ ```bash
62
+ /ping8: Pings 8.8.8.8 and returns the results.
63
+
64
+ /top: Runs the top command and returns the results.
65
+
66
+ /htop: Runs the htop command and returns the results.
67
+
68
+ /eval: Execute Python code and return the result (NEW!)
69
+
70
+ /help - Shows help and usage information.
71
+ ```
72
+
73
+ ** You can also run any Linux command by simply entering it in the Telegram chat with the bot.
74
+
75
+ ## Contributions
76
+
77
+ Contributions to this project are welcome! If you have ideas for new features or improvements, feel free to submit a pull request or open an issue.
78
+
79
+ ## License
80
+
81
+ This project is licensed under the MIT License.
addons.txt ADDED
@@ -0,0 +1,5 @@
 
 
 
 
 
 
1
+ # Additional add-ons and utilities
2
+ requests
3
+ beautifulsoup4
4
+ lxml
5
+ pillow
bot.py ADDED
@@ -0,0 +1,215 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env python3
2
+ # -*- coding: utf-8 -*-
3
+ """
4
+ Created on Wed Apr 4 19:06:08 2018
5
+
6
+ @author: mparvin
7
+ """
8
+
9
+ import subprocess
10
+ import configparser
11
+ import os
12
+ import sys
13
+ from telegram.ext import Updater, CommandHandler, MessageHandler, Filters
14
+ import logging
15
+
16
+
17
+ # Configure logging - reduce noise from telegram library
18
+ logging.basicConfig(
19
+ format="%(asctime)s - %(name)s - %(levelname)s - %(message)s", level=logging.INFO
20
+ )
21
+
22
+ # Suppress verbose logging from telegram and urllib3
23
+ logging.getLogger('telegram.vendor.ptb_urllib3.urllib3.connectionpool').setLevel(logging.ERROR)
24
+ logging.getLogger('telegram.ext.updater').setLevel(logging.ERROR)
25
+
26
+ logger = logging.getLogger(__name__)
27
+
28
+ # Try to read config file
29
+ config = configparser.ConfigParser()
30
+ try:
31
+ if not os.path.exists("config"):
32
+ logger.error("Config file not found. Please create a 'config' file based on config.example")
33
+ logger.info("Bot cannot start without configuration. Exiting gracefully...")
34
+ sys.exit(0) # Exit gracefully so the web server can continue
35
+
36
+ config.read("config")
37
+ ### Get admin chat_id from config file
38
+ ### For more security replies only send to admin chat_id
39
+ adminCID = config["SecretConfig"]["admincid"]
40
+ except (KeyError, configparser.Error) as e:
41
+ logger.error(f"Error reading config file: {e}")
42
+ logger.info("Bot cannot start without valid configuration. Exiting gracefully...")
43
+ sys.exit(0) # Exit gracefully so the web server can continue
44
+ ### This function run command and send output to user
45
+ def runCMD(bot, update):
46
+ if not isAdmin(bot, update):
47
+ return
48
+ usercommand = update.message.text
49
+ cmdProc = subprocess.Popen(
50
+ usercommand, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True
51
+ )
52
+ cmdOut, cmdErr = cmdProc.communicate()
53
+ if cmdOut:
54
+ bot.sendMessage(text=str(cmdOut, "utf-8"), chat_id=adminCID)
55
+ else:
56
+ bot.sendMessage(text=str(cmdErr, "utf-8"), chat_id=adminCID)
57
+
58
+
59
+ ### This function ping 8.8.8.8 and send you result
60
+ def ping8(bot, update):
61
+ if not isAdmin(bot, update):
62
+ return
63
+ cmdOut = str(
64
+ subprocess.check_output(
65
+ "ping 8.8.8.8 -c4", stderr=subprocess.STDOUT, shell=True
66
+ ),
67
+ "utf-8",
68
+ )
69
+ bot.sendMessage(text=cmdOut, chat_id=adminCID)
70
+
71
+
72
+ def startCMD(bot, update):
73
+ if not isAdmin(bot, update):
74
+ return
75
+ bot.sendMessage(
76
+ text="Welcome to TSMB bot, this is Linux server/PC manager, Please use /help and read carefully!!",
77
+ chat_id=adminCID,
78
+ )
79
+
80
+
81
+ def helpCMD(bot, update):
82
+ if not isAdmin(bot, update):
83
+ return
84
+ bot.sendMessage(
85
+ text="This bot has access to your server/PC, So it can do anything. Please use Telegram local password to prevent others from accessing to this bot.",
86
+ chat_id=adminCID,
87
+ )
88
+
89
+
90
+ def evalCMD(bot, update):
91
+ """Execute Python code and return the result
92
+
93
+ SECURITY NOTE: This command allows arbitrary Python code execution.
94
+ It is restricted to admin users only via isAdmin() check.
95
+ This is intentional for remote server management but should be used
96
+ with caution. Only authorized administrators should have access.
97
+ """
98
+ if not isAdmin(bot, update):
99
+ return
100
+
101
+ # Get the Python code from the message (remove /eval command)
102
+ code = update.message.text.replace("/eval", "", 1).strip()
103
+
104
+ if not code:
105
+ bot.sendMessage(
106
+ text="Please provide Python code to evaluate.\nUsage: /eval <python_code>",
107
+ chat_id=adminCID,
108
+ )
109
+ return
110
+
111
+ try:
112
+ # Create a safe namespace for eval
113
+ namespace = {
114
+ '__builtins__': __builtins__,
115
+ 'os': os,
116
+ 'subprocess': subprocess,
117
+ }
118
+
119
+ # Try to evaluate as expression first
120
+ try:
121
+ result = eval(code, namespace)
122
+ output = str(result)
123
+ except SyntaxError:
124
+ # If it fails, try to execute as statement
125
+ exec(code, namespace)
126
+ output = "Code executed successfully (no return value)"
127
+
128
+ bot.sendMessage(text=f"βœ… Result:\n{output}", chat_id=adminCID)
129
+ except Exception as e:
130
+ bot.sendMessage(text=f"❌ Error:\n{type(e).__name__}: {str(e)}", chat_id=adminCID)
131
+
132
+
133
+ def topCMD(bot, update):
134
+ if not isAdmin(bot, update):
135
+ return
136
+ cmdOut = str(subprocess.check_output("top -n 1", shell=True), "utf-8")
137
+ bot.sendMessage(text=cmdOut, chat_id=adminCID)
138
+
139
+
140
+ def HTopCMD(bot, update):
141
+ ## Is this user admin?
142
+ if not isAdmin(bot, update):
143
+ return
144
+ ## Checking requirements on your system
145
+ htopCheck = subprocess.call(["which", "htop"])
146
+ if htopCheck != 0:
147
+ bot.sendMessage(
148
+ text="htop is not installed on your system, Please install it first and try again",
149
+ chat_id=adminCID,
150
+ )
151
+ return
152
+ ahaCheck = subprocess.call(["which", "aha"])
153
+ if ahaCheck != 0:
154
+ bot.sendMessage(
155
+ text="aha is not installed on your system, Please install it first and try again",
156
+ chat_id=adminCID,
157
+ )
158
+ return
159
+ os.system("echo q | htop | aha --black --line-fix > ./htop-output.html")
160
+ with open("./htop-output.html", "rb") as fileToSend:
161
+ bot.sendDocument(document=fileToSend, chat_id=adminCID)
162
+ if os.path.exists("./htop-output.html"):
163
+ os.remove("./htop-output.html")
164
+
165
+
166
+ def error(bot, update, error):
167
+ """Log Errors caused by Updates."""
168
+ logger.warning('Update "%s" caused error "%s"', update, error)
169
+
170
+
171
+ def isAdmin(bot, update):
172
+ chat_id = update.message.chat_id
173
+ if str(chat_id) == adminCID:
174
+ return True
175
+
176
+ update.message.reply_text(
177
+ "You cannot use this bot, because you are not Admin!!!!"
178
+ )
179
+ alertMessage = """Some one try to use this bot with this information:\n chat_id is {} and username is {} """.format(
180
+ update.message.chat_id, update.message.from_user.username
181
+ )
182
+ bot.sendMessage(text=alertMessage, chat_id=adminCID)
183
+ return False
184
+
185
+
186
+ def main():
187
+ try:
188
+ logger.info("Starting Telegram bot...")
189
+ updater = Updater(config["SecretConfig"]["Token"])
190
+ dp = updater.dispatcher
191
+
192
+ dp.add_handler(CommandHandler("start", startCMD))
193
+ dp.add_handler(CommandHandler("ping8", ping8))
194
+ dp.add_handler(CommandHandler("top", topCMD))
195
+ dp.add_handler(CommandHandler("htop", HTopCMD))
196
+ dp.add_handler(CommandHandler("help", helpCMD))
197
+ dp.add_handler(CommandHandler("eval", evalCMD))
198
+ dp.add_handler(MessageHandler(Filters.text, runCMD))
199
+
200
+ dp.add_error_handler(error)
201
+
202
+ logger.info("Bot configured successfully. Starting polling...")
203
+ updater.start_polling()
204
+ logger.info("βœ… Telegram bot is now running and listening for commands!")
205
+ updater.idle()
206
+ except Exception as e:
207
+ logger.error(f"Failed to start Telegram bot: {type(e).__name__}: {str(e)}")
208
+ logger.info("This is normal if running in an environment without Telegram API access (e.g., Hugging Face Spaces)")
209
+ logger.info("The web server will continue to run. Configure the bot with valid credentials to enable Telegram functionality.")
210
+ # Exit gracefully - let the web server continue running
211
+ sys.exit(0)
212
+
213
+
214
+ if __name__ == "__main__":
215
+ main()
config.example ADDED
@@ -0,0 +1,4 @@
 
 
 
 
 
1
+ [SecretConfig]
2
+ token = 193025875:AAHZ3hIanIau-Hg04B-mZREFBjLl6GvM9fk
3
+ admincid = 131728488
4
+
reqs.txt ADDED
@@ -0,0 +1,15 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Core telegram requirements
2
+ python-telegram-bot==10.0.1
3
+ configparser==4.0.2
4
+ certifi==2024.7.4
5
+ future==0.18.3
6
+
7
+ # Web server requirements
8
+ fastapi<0.100.0
9
+ pydantic<2.0.0
10
+ uvicorn
11
+ python-multipart
12
+
13
+ # Additional utilities
14
+ redis
15
+ aiohttp
requirements.txt ADDED
@@ -0,0 +1,4 @@
 
 
 
 
 
1
+ certifi==2024.7.4
2
+ future==0.18.3
3
+ configparser==4.0.2
4
+ python-telegram-bot==10.0.1
server.py ADDED
@@ -0,0 +1,842 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env python3
2
+ # -*- coding: utf-8 -*-
3
+ """
4
+ Simple FastAPI server for Hugging Face Spaces
5
+ This keeps the space alive and provides a basic web interface
6
+ """
7
+
8
+ from fastapi import FastAPI, Request, HTTPException, Form, UploadFile, File
9
+ from fastapi.responses import HTMLResponse, JSONResponse
10
+ from fastapi.middleware.cors import CORSMiddleware
11
+ import uvicorn
12
+ import os
13
+ import logging
14
+ import subprocess
15
+ import configparser
16
+ import tempfile
17
+ import traceback
18
+
19
+ # Configure logging
20
+ logging.basicConfig(
21
+ format="%(asctime)s - %(name)s - %(levelname)s - %(message)s",
22
+ level=logging.INFO
23
+ )
24
+
25
+ logger = logging.getLogger(__name__)
26
+
27
+ app = FastAPI()
28
+
29
+ # Add CORS middleware
30
+ app.add_middleware(
31
+ CORSMiddleware,
32
+ allow_origins=["*"],
33
+ allow_credentials=True,
34
+ allow_methods=["*"],
35
+ allow_headers=["*"],
36
+ )
37
+
38
+ # Load config for authentication
39
+ def load_config():
40
+ """Load configuration file"""
41
+ config = configparser.ConfigParser()
42
+ if os.path.exists("config"):
43
+ config.read("config")
44
+ return config
45
+ return None
46
+
47
+ def verify_admin(chat_id: str):
48
+ """Verify if the provided chat_id matches admin"""
49
+ config = load_config()
50
+ if config and "SecretConfig" in config:
51
+ admin_cid = config["SecretConfig"].get("admincid", "")
52
+ return str(chat_id) == str(admin_cid)
53
+ # If no config, allow access for demo purposes in restricted environments
54
+ # WARNING: This is insecure in production. Always use a config file with proper admin_id
55
+ logger.warning("No config file found - running in insecure demo mode")
56
+ return True
57
+
58
+ @app.get("/", response_class=HTMLResponse)
59
+ async def root():
60
+ """Root endpoint that returns a professional web interface"""
61
+
62
+ # Check if config file exists
63
+ config_exists = os.path.exists("config")
64
+
65
+ return f"""
66
+ <!DOCTYPE html>
67
+ <html lang="en">
68
+ <head>
69
+ <meta charset="UTF-8">
70
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
71
+ <title>Telegram Server Manager - Web Console</title>
72
+ <style>
73
+ * {{
74
+ margin: 0;
75
+ padding: 0;
76
+ box-sizing: border-box;
77
+ }}
78
+
79
+ body {{
80
+ font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
81
+ background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
82
+ min-height: 100vh;
83
+ padding: 20px;
84
+ }}
85
+
86
+ .container {{
87
+ max-width: 1200px;
88
+ margin: 0 auto;
89
+ }}
90
+
91
+ .header {{
92
+ background: white;
93
+ padding: 25px;
94
+ border-radius: 10px;
95
+ box-shadow: 0 4px 6px rgba(0,0,0,0.1);
96
+ margin-bottom: 20px;
97
+ }}
98
+
99
+ .header h1 {{
100
+ color: #333;
101
+ font-size: 2em;
102
+ margin-bottom: 10px;
103
+ }}
104
+
105
+ .status-badge {{
106
+ display: inline-block;
107
+ padding: 8px 15px;
108
+ border-radius: 20px;
109
+ font-size: 0.9em;
110
+ font-weight: bold;
111
+ }}
112
+
113
+ .status-online {{
114
+ background: #d4edda;
115
+ color: #155724;
116
+ }}
117
+
118
+ .status-warning {{
119
+ background: #fff3cd;
120
+ color: #856404;
121
+ }}
122
+
123
+ .main-content {{
124
+ display: grid;
125
+ grid-template-columns: 1fr;
126
+ gap: 20px;
127
+ }}
128
+
129
+ @media (min-width: 768px) {{
130
+ .main-content {{
131
+ grid-template-columns: 1fr 1fr;
132
+ }}
133
+ }}
134
+
135
+ .card {{
136
+ background: white;
137
+ padding: 25px;
138
+ border-radius: 10px;
139
+ box-shadow: 0 4px 6px rgba(0,0,0,0.1);
140
+ }}
141
+
142
+ .card h2 {{
143
+ color: #333;
144
+ margin-bottom: 15px;
145
+ font-size: 1.5em;
146
+ border-bottom: 2px solid #667eea;
147
+ padding-bottom: 10px;
148
+ }}
149
+
150
+ .form-group {{
151
+ margin-bottom: 15px;
152
+ }}
153
+
154
+ label {{
155
+ display: block;
156
+ margin-bottom: 5px;
157
+ color: #555;
158
+ font-weight: 600;
159
+ }}
160
+
161
+ input[type="text"],
162
+ input[type="password"],
163
+ textarea,
164
+ select {{
165
+ width: 100%;
166
+ padding: 10px;
167
+ border: 2px solid #e0e0e0;
168
+ border-radius: 5px;
169
+ font-size: 1em;
170
+ font-family: inherit;
171
+ transition: border-color 0.3s;
172
+ }}
173
+
174
+ input:focus,
175
+ textarea:focus,
176
+ select:focus {{
177
+ outline: none;
178
+ border-color: #667eea;
179
+ }}
180
+
181
+ textarea {{
182
+ min-height: 120px;
183
+ font-family: 'Courier New', monospace;
184
+ resize: vertical;
185
+ }}
186
+
187
+ button {{
188
+ background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
189
+ color: white;
190
+ border: none;
191
+ padding: 12px 25px;
192
+ border-radius: 5px;
193
+ font-size: 1em;
194
+ font-weight: 600;
195
+ cursor: pointer;
196
+ transition: transform 0.2s, box-shadow 0.2s;
197
+ }}
198
+
199
+ button:hover {{
200
+ transform: translateY(-2px);
201
+ box-shadow: 0 4px 8px rgba(0,0,0,0.2);
202
+ }}
203
+
204
+ button:active {{
205
+ transform: translateY(0);
206
+ }}
207
+
208
+ button:disabled {{
209
+ background: #ccc;
210
+ cursor: not-allowed;
211
+ transform: none;
212
+ }}
213
+
214
+ .output {{
215
+ background: #1e1e1e;
216
+ color: #d4d4d4;
217
+ padding: 15px;
218
+ border-radius: 5px;
219
+ font-family: 'Courier New', monospace;
220
+ font-size: 0.9em;
221
+ max-height: 400px;
222
+ overflow-y: auto;
223
+ white-space: pre-wrap;
224
+ word-wrap: break-word;
225
+ margin-top: 15px;
226
+ }}
227
+
228
+ .output.empty {{
229
+ color: #888;
230
+ font-style: italic;
231
+ }}
232
+
233
+ .loading {{
234
+ display: inline-block;
235
+ width: 20px;
236
+ height: 20px;
237
+ border: 3px solid rgba(255,255,255,.3);
238
+ border-radius: 50%;
239
+ border-top-color: white;
240
+ animation: spin 1s ease-in-out infinite;
241
+ }}
242
+
243
+ @keyframes spin {{
244
+ to {{ transform: rotate(360deg); }}
245
+ }}
246
+
247
+ .info-box {{
248
+ background: #e7f3ff;
249
+ border-left: 4px solid #2196F3;
250
+ padding: 15px;
251
+ margin: 15px 0;
252
+ border-radius: 5px;
253
+ }}
254
+
255
+ .warning-box {{
256
+ background: #fff3cd;
257
+ border-left: 4px solid #ffc107;
258
+ padding: 15px;
259
+ margin: 15px 0;
260
+ border-radius: 5px;
261
+ }}
262
+
263
+ .success-box {{
264
+ background: #d4edda;
265
+ border-left: 4px solid #28a745;
266
+ padding: 15px;
267
+ margin: 15px 0;
268
+ border-radius: 5px;
269
+ }}
270
+
271
+ .error-box {{
272
+ background: #f8d7da;
273
+ border-left: 4px solid #dc3545;
274
+ padding: 15px;
275
+ margin: 15px 0;
276
+ border-radius: 5px;
277
+ }}
278
+
279
+ .file-upload {{
280
+ border: 2px dashed #667eea;
281
+ padding: 20px;
282
+ text-align: center;
283
+ border-radius: 5px;
284
+ cursor: pointer;
285
+ transition: background 0.3s;
286
+ }}
287
+
288
+ .file-upload:hover {{
289
+ background: #f0f0f0;
290
+ }}
291
+
292
+ .tabs {{
293
+ display: flex;
294
+ gap: 10px;
295
+ margin-bottom: 20px;
296
+ border-bottom: 2px solid #e0e0e0;
297
+ }}
298
+
299
+ .tab {{
300
+ padding: 10px 20px;
301
+ cursor: pointer;
302
+ border: none;
303
+ background: none;
304
+ font-weight: 600;
305
+ color: #666;
306
+ border-bottom: 3px solid transparent;
307
+ transition: all 0.3s;
308
+ }}
309
+
310
+ .tab.active {{
311
+ color: #667eea;
312
+ border-bottom-color: #667eea;
313
+ }}
314
+
315
+ .tab-content {{
316
+ display: none;
317
+ }}
318
+
319
+ .tab-content.active {{
320
+ display: block;
321
+ }}
322
+ </style>
323
+ </head>
324
+ <body>
325
+ <div class="container">
326
+ <div class="header">
327
+ <h1>πŸš€ Telegram Server Manager</h1>
328
+ <span class="status-badge {'status-online' if config_exists else 'status-warning'}">
329
+ {'βœ… Web Console Active' if config_exists else '⚠️ Demo Mode'}
330
+ </span>
331
+ <p style="margin-top: 10px; color: #666;">Professional web interface for server management</p>
332
+ </div>
333
+
334
+ {'<div class="warning-box"><strong>⚠️ Demo Mode:</strong> Config file not found. Some features may be restricted. Create a <code>config</code> file to enable full functionality.</div>' if not config_exists else ''}
335
+
336
+ <div class="main-content">
337
+ <!-- Command Execution Card -->
338
+ <div class="card">
339
+ <h2>πŸ’» Command Executor</h2>
340
+ <div class="info-box">
341
+ <strong>πŸ’‘ Tip:</strong> Run any shell command directly from the browser
342
+ </div>
343
+
344
+ <div class="form-group">
345
+ <label for="cmd-input">Command:</label>
346
+ <input type="text" id="cmd-input" placeholder="ls -la" />
347
+ </div>
348
+
349
+ <button onclick="runCommand()" id="cmd-btn">
350
+ Execute Command
351
+ </button>
352
+
353
+ <div class="output empty" id="cmd-output">
354
+ Output will appear here...
355
+ </div>
356
+ </div>
357
+
358
+ <!-- Python Evaluator Card -->
359
+ <div class="card">
360
+ <h2>🐍 Python Evaluator</h2>
361
+ <div class="info-box">
362
+ <strong>πŸ’‘ Tip:</strong> Execute Python code with full system access
363
+ </div>
364
+
365
+ <div class="form-group">
366
+ <label for="py-input">Python Code:</label>
367
+ <textarea id="py-input" placeholder="print('Hello World')&#x0a;import os&#x0a;print(os.getcwd())"></textarea>
368
+ </div>
369
+
370
+ <button onclick="runPython()" id="py-btn">
371
+ Execute Python
372
+ </button>
373
+
374
+ <div class="output empty" id="py-output">
375
+ Output will appear here...
376
+ </div>
377
+ </div>
378
+
379
+ <!-- File Uploader Card -->
380
+ <div class="card">
381
+ <h2>πŸ“ Python File Executor</h2>
382
+ <div class="info-box">
383
+ <strong>πŸ’‘ Tip:</strong> Upload and run Python files
384
+ </div>
385
+
386
+ <div class="form-group">
387
+ <label>Upload Python File (.py):</label>
388
+ <input type="file" id="file-input" accept=".py" style="margin-bottom: 10px;" />
389
+ </div>
390
+
391
+ <button onclick="uploadAndRun()" id="file-btn">
392
+ Upload & Execute
393
+ </button>
394
+
395
+ <div class="output empty" id="file-output">
396
+ Output will appear here...
397
+ </div>
398
+ </div>
399
+
400
+ <!-- System Info Card -->
401
+ <div class="card">
402
+ <h2>πŸ“Š Quick System Info</h2>
403
+
404
+ <div class="tabs">
405
+ <button class="tab active" onclick="showTab('system')">System</button>
406
+ <button class="tab" onclick="showTab('disk')">Disk</button>
407
+ <button class="tab" onclick="showTab('network')">Network</button>
408
+ </div>
409
+
410
+ <div id="system" class="tab-content active">
411
+ <button onclick="getSystemInfo('uname -a')" style="width: 100%; margin-bottom: 10px;">
412
+ System Information
413
+ </button>
414
+ <button onclick="getSystemInfo('df -h')" style="width: 100%; margin-bottom: 10px;">
415
+ Disk Usage
416
+ </button>
417
+ <button onclick="getSystemInfo('free -h')" style="width: 100%;">
418
+ Memory Usage
419
+ </button>
420
+ </div>
421
+
422
+ <div id="disk" class="tab-content">
423
+ <button onclick="getSystemInfo('du -sh /* 2>/dev/null')" style="width: 100%; margin-bottom: 10px;">
424
+ Root Directories Size
425
+ </button>
426
+ <button onclick="getSystemInfo('lsblk')" style="width: 100%;">
427
+ Block Devices
428
+ </button>
429
+ </div>
430
+
431
+ <div id="network" class="tab-content">
432
+ <button onclick="getSystemInfo('ip addr')" style="width: 100%; margin-bottom: 10px;">
433
+ IP Addresses
434
+ </button>
435
+ <button onclick="getSystemInfo('ping -c 4 8.8.8.8')" style="width: 100%;">
436
+ Network Test (ping)
437
+ </button>
438
+ </div>
439
+
440
+ <div class="output empty" id="sys-output">
441
+ Click a button to see system info...
442
+ </div>
443
+ </div>
444
+ </div>
445
+
446
+ <div class="warning-box" style="margin-top: 20px;">
447
+ <h4>πŸ”’ Security Notice:</h4>
448
+ <p><strong>⚠️ IMPORTANT:</strong> This web interface provides full system access and is designed for trusted environments only.</p>
449
+ <p>In production environments:</p>
450
+ <ul style="margin-left: 20px; margin-top: 10px;">
451
+ <li>Use strong authentication (configure admin chat ID in config file)</li>
452
+ <li>Deploy behind a reverse proxy with HTTPS</li>
453
+ <li>Implement rate limiting and input validation</li>
454
+ <li>Monitor and log all command executions</li>
455
+ <li>Restrict network access to trusted IPs only</li>
456
+ </ul>
457
+ <p style="margin-top: 10px;"><strong>Note:</strong> This tool intentionally allows shell command execution and Python eval - features equivalent to the Telegram bot. Use responsibly.</p>
458
+ </div>
459
+ </div>
460
+
461
+ <script>
462
+ function showTab(tabName) {{
463
+ // Hide all tab contents
464
+ document.querySelectorAll('.tab-content').forEach(content => {{
465
+ content.classList.remove('active');
466
+ }});
467
+
468
+ // Remove active class from all tabs
469
+ document.querySelectorAll('.tab').forEach(tab => {{
470
+ tab.classList.remove('active');
471
+ }});
472
+
473
+ // Show selected tab
474
+ document.getElementById(tabName).classList.add('active');
475
+ event.target.classList.add('active');
476
+ }}
477
+
478
+ async function runCommand() {{
479
+ const input = document.getElementById('cmd-input');
480
+ const output = document.getElementById('cmd-output');
481
+ const btn = document.getElementById('cmd-btn');
482
+
483
+ const command = input.value.trim();
484
+ if (!command) {{
485
+ output.textContent = '❌ Please enter a command';
486
+ output.classList.remove('empty');
487
+ return;
488
+ }}
489
+
490
+ btn.disabled = true;
491
+ btn.innerHTML = '<span class="loading"></span> Executing...';
492
+ output.textContent = 'Executing command...';
493
+ output.classList.remove('empty');
494
+
495
+ try {{
496
+ const response = await fetch('/api/execute', {{
497
+ method: 'POST',
498
+ headers: {{ 'Content-Type': 'application/json' }},
499
+ body: JSON.stringify({{ command: command, admin_id: 'web-console' }})
500
+ }});
501
+
502
+ const data = await response.json();
503
+
504
+ if (data.success) {{
505
+ output.textContent = 'βœ… Command executed successfully:\\n\\n' + data.output;
506
+ }} else {{
507
+ output.textContent = '❌ Error:\\n\\n' + data.error;
508
+ }}
509
+ }} catch (error) {{
510
+ output.textContent = '❌ Network error: ' + error.message;
511
+ }} finally {{
512
+ btn.disabled = false;
513
+ btn.innerHTML = 'Execute Command';
514
+ }}
515
+ }}
516
+
517
+ async function runPython() {{
518
+ const input = document.getElementById('py-input');
519
+ const output = document.getElementById('py-output');
520
+ const btn = document.getElementById('py-btn');
521
+
522
+ const code = input.value.trim();
523
+ if (!code) {{
524
+ output.textContent = '❌ Please enter Python code';
525
+ output.classList.remove('empty');
526
+ return;
527
+ }}
528
+
529
+ btn.disabled = true;
530
+ btn.innerHTML = '<span class="loading"></span> Executing...';
531
+ output.textContent = 'Executing Python code...';
532
+ output.classList.remove('empty');
533
+
534
+ try {{
535
+ const response = await fetch('/api/eval', {{
536
+ method: 'POST',
537
+ headers: {{ 'Content-Type': 'application/json' }},
538
+ body: JSON.stringify({{ code: code, admin_id: 'web-console' }})
539
+ }});
540
+
541
+ const data = await response.json();
542
+
543
+ if (data.success) {{
544
+ output.textContent = 'βœ… Python executed successfully:\\n\\n' + data.output;
545
+ }} else {{
546
+ output.textContent = '❌ Error:\\n\\n' + data.error;
547
+ }}
548
+ }} catch (error) {{
549
+ output.textContent = '❌ Network error: ' + error.message;
550
+ }} finally {{
551
+ btn.disabled = false;
552
+ btn.innerHTML = 'Execute Python';
553
+ }}
554
+ }}
555
+
556
+ async function uploadAndRun() {{
557
+ const input = document.getElementById('file-input');
558
+ const output = document.getElementById('file-output');
559
+ const btn = document.getElementById('file-btn');
560
+
561
+ if (!input.files || input.files.length === 0) {{
562
+ output.textContent = '❌ Please select a Python file';
563
+ output.classList.remove('empty');
564
+ return;
565
+ }}
566
+
567
+ const file = input.files[0];
568
+ if (!file.name.endsWith('.py')) {{
569
+ output.textContent = '❌ Please select a .py file';
570
+ output.classList.remove('empty');
571
+ return;
572
+ }}
573
+
574
+ btn.disabled = true;
575
+ btn.innerHTML = '<span class="loading"></span> Uploading & Executing...';
576
+ output.textContent = 'Uploading and executing file...';
577
+ output.classList.remove('empty');
578
+
579
+ try {{
580
+ const formData = new FormData();
581
+ formData.append('file', file);
582
+ formData.append('admin_id', 'web-console');
583
+
584
+ const response = await fetch('/api/run-file', {{
585
+ method: 'POST',
586
+ body: formData
587
+ }});
588
+
589
+ const data = await response.json();
590
+
591
+ if (data.success) {{
592
+ output.textContent = 'βœ… File executed successfully:\\n\\n' + data.output;
593
+ }} else {{
594
+ output.textContent = '❌ Error:\\n\\n' + data.error;
595
+ }}
596
+ }} catch (error) {{
597
+ output.textContent = '❌ Network error: ' + error.message;
598
+ }} finally {{
599
+ btn.disabled = false;
600
+ btn.innerHTML = 'Upload & Execute';
601
+ }}
602
+ }}
603
+
604
+ async function getSystemInfo(command) {{
605
+ const output = document.getElementById('sys-output');
606
+ output.textContent = 'Loading...';
607
+ output.classList.remove('empty');
608
+
609
+ try {{
610
+ const response = await fetch('/api/execute', {{
611
+ method: 'POST',
612
+ headers: {{ 'Content-Type': 'application/json' }},
613
+ body: JSON.stringify({{ command: command, admin_id: 'web-console' }})
614
+ }});
615
+
616
+ const data = await response.json();
617
+
618
+ if (data.success) {{
619
+ output.textContent = data.output;
620
+ }} else {{
621
+ output.textContent = '❌ Error: ' + data.error;
622
+ }}
623
+ }} catch (error) {{
624
+ output.textContent = '❌ Network error: ' + error.message;
625
+ }}
626
+ }}
627
+
628
+ // Enable Enter key for command input
629
+ document.getElementById('cmd-input').addEventListener('keypress', function(e) {{
630
+ if (e.key === 'Enter') {{
631
+ runCommand();
632
+ }}
633
+ }});
634
+ </script>
635
+ </body>
636
+ </html>
637
+ """
638
+
639
+ @app.post("/api/execute")
640
+ async def execute_command(request: Request):
641
+ """Execute a shell command"""
642
+ try:
643
+ data = await request.json()
644
+ command = data.get("command", "").strip()
645
+ admin_id = data.get("admin_id", "")
646
+
647
+ if not command:
648
+ return JSONResponse({"success": False, "error": "No command provided"})
649
+
650
+ # Verify admin (basic check)
651
+ if not verify_admin(admin_id):
652
+ return JSONResponse({"success": False, "error": "Unauthorized"})
653
+
654
+ logger.info(f"Executing command: {command}")
655
+
656
+ # Execute command with timeout
657
+ try:
658
+ result = subprocess.run(
659
+ command,
660
+ shell=True,
661
+ capture_output=True,
662
+ text=True,
663
+ timeout=30
664
+ )
665
+
666
+ output = result.stdout if result.stdout else result.stderr
667
+ if not output:
668
+ output = "Command executed successfully (no output)"
669
+
670
+ return JSONResponse({
671
+ "success": True,
672
+ "output": output,
673
+ "return_code": result.returncode
674
+ })
675
+
676
+ except subprocess.TimeoutExpired:
677
+ return JSONResponse({
678
+ "success": False,
679
+ "error": "Command timed out after 30 seconds"
680
+ })
681
+ except Exception as e:
682
+ return JSONResponse({
683
+ "success": False,
684
+ "error": f"Execution error: {str(e)}"
685
+ })
686
+
687
+ except Exception as e:
688
+ logger.error(f"Error in execute_command: {e}")
689
+ return JSONResponse({
690
+ "success": False,
691
+ "error": f"Server error: {str(e)}"
692
+ })
693
+
694
+ @app.post("/api/eval")
695
+ async def evaluate_python(request: Request):
696
+ """Execute Python code"""
697
+ try:
698
+ data = await request.json()
699
+ code = data.get("code", "").strip()
700
+ admin_id = data.get("admin_id", "")
701
+
702
+ if not code:
703
+ return JSONResponse({"success": False, "error": "No code provided"})
704
+
705
+ # Verify admin
706
+ if not verify_admin(admin_id):
707
+ return JSONResponse({"success": False, "error": "Unauthorized"})
708
+
709
+ logger.info(f"Executing Python code (length: {len(code)})")
710
+
711
+ try:
712
+ # Create a namespace for execution
713
+ namespace = {
714
+ '__builtins__': __builtins__,
715
+ 'os': os,
716
+ 'subprocess': subprocess,
717
+ }
718
+
719
+ # Capture stdout
720
+ import sys
721
+ from io import StringIO
722
+
723
+ old_stdout = sys.stdout
724
+ sys.stdout = StringIO()
725
+
726
+ try:
727
+ # Try to evaluate as expression first
728
+ try:
729
+ result = eval(code, namespace)
730
+ if result is not None:
731
+ print(result)
732
+ except SyntaxError:
733
+ # If it fails, execute as statement
734
+ exec(code, namespace)
735
+
736
+ output = sys.stdout.getvalue()
737
+ if not output:
738
+ output = "Code executed successfully (no output)"
739
+
740
+ return JSONResponse({
741
+ "success": True,
742
+ "output": output
743
+ })
744
+
745
+ finally:
746
+ sys.stdout = old_stdout
747
+
748
+ except Exception as e:
749
+ return JSONResponse({
750
+ "success": False,
751
+ "error": f"{type(e).__name__}: {str(e)}\\n{traceback.format_exc()}"
752
+ })
753
+
754
+ except Exception as e:
755
+ logger.error(f"Error in evaluate_python: {e}")
756
+ return JSONResponse({
757
+ "success": False,
758
+ "error": f"Server error: {str(e)}"
759
+ })
760
+
761
+ @app.post("/api/run-file")
762
+ async def run_python_file(file: UploadFile = File(...), admin_id: str = Form(...)):
763
+ """Upload and execute a Python file"""
764
+ try:
765
+ # Verify admin
766
+ if not verify_admin(admin_id):
767
+ return JSONResponse({"success": False, "error": "Unauthorized"})
768
+
769
+ # Verify file type
770
+ if not file.filename.endswith('.py'):
771
+ return JSONResponse({
772
+ "success": False,
773
+ "error": "Only .py files are allowed"
774
+ })
775
+
776
+ logger.info(f"Executing uploaded file: {file.filename}")
777
+
778
+ # Save file to temp location
779
+ with tempfile.NamedTemporaryFile(mode='w', suffix='.py', delete=False) as tmp:
780
+ content = await file.read()
781
+ tmp.write(content.decode('utf-8'))
782
+ tmp_path = tmp.name
783
+
784
+ try:
785
+ # Execute the file
786
+ result = subprocess.run(
787
+ ['python3', tmp_path], # Use python3 from PATH instead of hardcoded path
788
+ capture_output=True,
789
+ text=True,
790
+ timeout=30
791
+ )
792
+
793
+ output = result.stdout if result.stdout else result.stderr
794
+ if not output:
795
+ output = "File executed successfully (no output)"
796
+
797
+ return JSONResponse({
798
+ "success": True,
799
+ "output": output,
800
+ "return_code": result.returncode,
801
+ "filename": file.filename
802
+ })
803
+
804
+ except subprocess.TimeoutExpired:
805
+ return JSONResponse({
806
+ "success": False,
807
+ "error": "Execution timed out after 30 seconds"
808
+ })
809
+ finally:
810
+ # Clean up temp file
811
+ try:
812
+ os.unlink(tmp_path)
813
+ except (FileNotFoundError, PermissionError) as e:
814
+ logger.warning(f"Could not delete temp file {tmp_path}: {e}")
815
+
816
+ except Exception as e:
817
+ logger.error(f"Error in run_python_file: {e}")
818
+ return JSONResponse({
819
+ "success": False,
820
+ "error": f"Server error: {str(e)}"
821
+ })
822
+
823
+ @app.get("/health")
824
+ async def health():
825
+ """Health check endpoint"""
826
+ return {"status": "healthy", "bot": "running"}
827
+
828
+ @app.get("/api/status")
829
+ async def status():
830
+ """Status endpoint"""
831
+ return {
832
+ "status": "online",
833
+ "service": "Telegram Server Manager Bot",
834
+ "port": 7860,
835
+ "web_console": "enabled"
836
+ }
837
+
838
+ if __name__ == "__main__":
839
+ # Run on port 7860 for Hugging Face Spaces
840
+ port = int(os.environ.get("PORT", 7860))
841
+ logger.info(f"Starting web server on port {port}...")
842
+ uvicorn.run(app, host="0.0.0.0", port=port)
start.sh ADDED
@@ -0,0 +1,27 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/bin/bash
2
+
3
+ set -e # Exit on error
4
+
5
+ echo "πŸš€ Starting Telegram Server Manager Bot..."
6
+ echo "πŸ”„ Cleaning old session files..."
7
+
8
+ # Delete old session files
9
+ find . -name "*.session" -type f -delete || echo "No session files to clean"
10
+
11
+ echo "🌐 Starting web server..."
12
+ # Start the FastAPI server in the background
13
+ python3 server.py &
14
+ SERVER_PID=$!
15
+
16
+ # Check if server started successfully
17
+ sleep 2
18
+ if ! kill -0 $SERVER_PID 2>/dev/null; then
19
+ echo "❌ Failed to start web server"
20
+ exit 1
21
+ fi
22
+
23
+ echo "βœ… Web server started (PID: $SERVER_PID)"
24
+ echo "πŸ€– Starting Telegram bot..."
25
+
26
+ # Start the Telegram bot
27
+ python3 bot.py