feat: Веб-интерфейс - логин/пароль в .env + API команд
✅ WEB_ADMIN_LOGIN/PASSWORD в .env.example ✅ Конфиг web_admin в config.py ✅ API /api/command - выполнение команд ✅ API /api/commands - список команд ✅ Обновлён web_server.py с конфигом 📦 Бекап: backups/versions/v2.1.2_web_auth_2026-02-28/ Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
This commit is contained in:
parent
af4e7d2c5d
commit
fc7484889c
5 changed files with 171 additions and 17 deletions
|
|
@ -36,3 +36,9 @@ USE_PROXY=true
|
|||
PROXY_TYPE=socks5 # socks5 или http
|
||||
PROXY_HOST=127.0.0.1
|
||||
PROXY_PORT=10808 # SOCKS5 порт (или 10809 для HTTP)
|
||||
|
||||
# ===== ВЕБ-ИНТЕРФЕЙС АДМИНА =====
|
||||
WEB_ADMIN_LOGIN=admin
|
||||
WEB_ADMIN_PASSWORD=5nMVkjd5nMVkjd
|
||||
WEB_ADMIN_HOST=0.0.0.0
|
||||
WEB_ADMIN_PORT=8000
|
||||
|
|
|
|||
51
.env.web
Normal file
51
.env.web
Normal file
|
|
@ -0,0 +1,51 @@
|
|||
# Telegram Bot Token (получить у @BotFather)
|
||||
BOT_TOKEN=1234567890:ABCdefGHIjklMNOpqrsTUVwxyz
|
||||
|
||||
# ID чата дома (можно узнать через @userinfobot или переслав сообщение из чата)
|
||||
ADMIN_CHAT_ID=-1001234567890
|
||||
|
||||
# Ваш Telegram ID (админ) - узнать через @userinfobot
|
||||
ADMIN_USER_ID=123456789
|
||||
|
||||
# Путь к базе данных
|
||||
DATABASE_PATH=./database/domovoy.db
|
||||
|
||||
# Директория для экспортов
|
||||
EXPORT_DIR=./exports
|
||||
|
||||
# Расписание экспорта (cron формат: минута час день месяц день_недели)
|
||||
# Каждое воскресенье в 03:00
|
||||
EXPORT_SCHEDULE=0 3 * * 0
|
||||
|
||||
# Детект шпионов
|
||||
SPY_DETECTION_ENABLED=true
|
||||
|
||||
# Куда слать уведомления о шпионах (ваш ID)
|
||||
SPY_ALERT_USER_ID=123456789
|
||||
|
||||
# Дополнительные админы (через запятую, если будут)
|
||||
EXTRA_ADMIN_IDS=
|
||||
|
||||
# Логирование
|
||||
LOG_LEVEL=INFO
|
||||
LOG_FILE=./logs/bot.log
|
||||
|
||||
# ===== ПРОКСИ ДЛЯ ОБХОДА БЛОКИРОВОК РКН =====
|
||||
# xray на хосте: SOCKS5 порт 10808, HTTP порт 10809
|
||||
USE_PROXY=true
|
||||
PROXY_TYPE=socks5 # socks5 или http
|
||||
PROXY_HOST=127.0.0.1
|
||||
PROXY_PORT=10808 # SOCKS5 порт (или 10809 для HTTP)
|
||||
|
||||
# ===== ВЕБ-ИНТЕРФЕЙС АДМИНА =====
|
||||
WEB_ADMIN_LOGIN=admin
|
||||
WEB_ADMIN_PASSWORD=5nMVkjd5nMVkjd
|
||||
WEB_ADMIN_HOST=0.0.0.0
|
||||
WEB_ADMIN_PORT=8000
|
||||
|
||||
# ===== ВЕБ-ИНТЕРФЕЙС АДМИНА =====
|
||||
WEB_ADMIN_LOGIN=admin
|
||||
WEB_ADMIN_PASSWORD=5nMVkjd5nMVkjd
|
||||
WEB_ADMIN_HOST=0.0.0.0
|
||||
WEB_ADMIN_PORT=8000
|
||||
|
||||
|
|
@ -35,6 +35,12 @@ PROXY_TYPE = os.getenv('PROXY_TYPE', 'socks5').lower()
|
|||
PROXY_HOST = os.getenv('PROXY_HOST', '127.0.0.1')
|
||||
PROXY_PORT = int(os.getenv('PROXY_PORT', '10808'))
|
||||
|
||||
# ===== ВЕБ-ИНТЕРФЕЙС =====
|
||||
WEB_ADMIN_LOGIN = os.getenv('WEB_ADMIN_LOGIN', 'admin')
|
||||
WEB_ADMIN_PASSWORD = os.getenv('WEB_ADMIN_PASSWORD', 'admin')
|
||||
WEB_ADMIN_HOST = os.getenv('WEB_ADMIN_HOST', '0.0.0.0')
|
||||
WEB_ADMIN_PORT = int(os.getenv('WEB_ADMIN_PORT', '8000'))
|
||||
|
||||
# Проверка критичных настроек
|
||||
if not BOT_TOKEN:
|
||||
raise ValueError('BOT_TOKEN не настроен! Проверьте .env файл')
|
||||
|
|
|
|||
|
|
@ -11,9 +11,11 @@ logger = logging.getLogger(__name__)
|
|||
class WebServerService:
|
||||
"""Сервис для управления веб-сервером"""
|
||||
|
||||
def __init__(self, host: str = "0.0.0.0", port: int = 8000):
|
||||
self.host = host
|
||||
self.port = port
|
||||
def __init__(self, host: str = None, port: int = None):
|
||||
# Импортируем конфиг при инициализации
|
||||
import config
|
||||
self.host = host or config.WEB_ADMIN_HOST
|
||||
self.port = port or config.WEB_ADMIN_PORT
|
||||
self.server = None
|
||||
self.thread: Optional[threading.Thread] = None
|
||||
self.is_running = False
|
||||
|
|
@ -27,6 +29,7 @@ class WebServerService:
|
|||
try:
|
||||
import uvicorn
|
||||
from web.app import app
|
||||
import config
|
||||
|
||||
def run_server():
|
||||
uvicorn.run(app, host=self.host, port=self.port, log_level="info")
|
||||
|
|
@ -36,8 +39,8 @@ class WebServerService:
|
|||
self.is_running = True
|
||||
|
||||
logger.info(f"✅ Веб-сервер запущен на http://{self.host}:{self.port}")
|
||||
logger.info(f" Логин: admin")
|
||||
logger.info(f" Пароль: {self.port} (ID админа)")
|
||||
logger.info(f" Логин: {config.WEB_ADMIN_LOGIN}")
|
||||
logger.info(f" Пароль: {config.WEB_ADMIN_PASSWORD}")
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Ошибка запуска веб-сервера: {e}")
|
||||
|
|
|
|||
94
web/app.py
94
web/app.py
|
|
@ -42,8 +42,8 @@ security = HTTPBasic()
|
|||
|
||||
def get_current_admin(credentials: HTTPBasicCredentials = Depends(security)):
|
||||
"""Проверка админа"""
|
||||
correct_username = secrets.compare_digest(credentials.username, "admin")
|
||||
correct_password = secrets.compare_digest(credentials.password, str(config.ADMIN_USER_ID))
|
||||
correct_username = secrets.compare_digest(credentials.username, config.WEB_ADMIN_LOGIN)
|
||||
correct_password = secrets.compare_digest(credentials.password, config.WEB_ADMIN_PASSWORD)
|
||||
|
||||
if not (correct_username and correct_password):
|
||||
raise HTTPException(
|
||||
|
|
@ -258,11 +258,99 @@ async def settings_page(request: Request, username: str = Depends(get_current_ad
|
|||
"bot_token": config.BOT_TOKEN[:20] + "...",
|
||||
"admin_chat_id": config.ADMIN_CHAT_ID,
|
||||
"admin_user_id": config.ADMIN_USER_ID,
|
||||
"use_proxy": config.USE_PROXY
|
||||
"use_proxy": config.USE_PROXY,
|
||||
"web_login": config.WEB_ADMIN_LOGIN,
|
||||
"web_password": config.WEB_ADMIN_PASSWORD
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
# =============================================================================
|
||||
# API - КОМАНДЫ БОТА
|
||||
# =============================================================================
|
||||
|
||||
@app.post("/api/command")
|
||||
async def api_command(
|
||||
request: Request,
|
||||
username: str = Depends(get_current_admin)
|
||||
):
|
||||
"""Выполнить команду бота"""
|
||||
import json
|
||||
from aiogram import Bot
|
||||
|
||||
data = await request.json()
|
||||
command = data.get('command', '')
|
||||
args = data.get('args', '')
|
||||
|
||||
if not command:
|
||||
return JSONResponse({"success": False, "error": "Нет команды"})
|
||||
|
||||
try:
|
||||
# Создаём бота
|
||||
bot = Bot(token=config.BOT_TOKEN)
|
||||
|
||||
# Формируем полное сообщение команды
|
||||
full_command = f"/{command}"
|
||||
if args:
|
||||
full_command += f" {args}"
|
||||
|
||||
# Отправляем команду в чат админа
|
||||
result = await bot.send_message(
|
||||
config.ADMIN_CHAT_ID,
|
||||
full_command
|
||||
)
|
||||
|
||||
await bot.session.close()
|
||||
|
||||
return JSONResponse({
|
||||
"success": True,
|
||||
"message": f"Команда /{command} отправлена",
|
||||
"result_id": result.message_id
|
||||
})
|
||||
except Exception as e:
|
||||
return JSONResponse({
|
||||
"success": False,
|
||||
"error": str(e)
|
||||
}, status_code=500)
|
||||
|
||||
|
||||
@app.get("/api/commands")
|
||||
async def api_commands_list(username: str = Depends(get_current_admin)):
|
||||
"""Список доступных команд"""
|
||||
commands = {
|
||||
"admin": [
|
||||
{"cmd": "admin", "desc": "Админ-панель"},
|
||||
{"cmd": "stats", "desc": "Статистика чата"},
|
||||
{"cmd": "spies", "desc": "Подозрительные пользователи"},
|
||||
{"cmd": "users", "desc": "Список жильцов"},
|
||||
{"cmd": "verify", "desc": "Заявки на верификацию"},
|
||||
{"cmd": "export", "desc": "Экспорт данных"},
|
||||
{"cmd": "rating", "desc": "Рейтинг пользователей"},
|
||||
],
|
||||
"initiative_group": [
|
||||
{"cmd": "ig_add", "desc": "Добавить в ИГ"},
|
||||
{"cmd": "ig_remove", "desc": "Удалить из ИГ"},
|
||||
{"cmd": "ig_list", "desc": "Список ИГ"},
|
||||
{"cmd": "ig_stats", "desc": "Статистика ИГ"},
|
||||
{"cmd": "ig_check", "desc": "Проверка участника"},
|
||||
{"cmd": "ig_broadcast", "desc": "Рассылка для ИГ"},
|
||||
],
|
||||
"events": [
|
||||
{"cmd": "event_add", "desc": "Добавить событие"},
|
||||
{"cmd": "events", "desc": "Список событий"},
|
||||
{"cmd": "participants", "desc": "Участники события"},
|
||||
{"cmd": "event_cancel", "desc": "Отменить событие"},
|
||||
],
|
||||
"security": [
|
||||
{"cmd": "unverify", "desc": "Отозвать верификацию"},
|
||||
{"cmd": "unverified_list", "desc": "Список не верифицированных"},
|
||||
{"cmd": "ban", "desc": "Забанить пользователя"},
|
||||
{"cmd": "unban", "desc": "Разбанить"},
|
||||
]
|
||||
}
|
||||
return JSONResponse({"commands": commands})
|
||||
|
||||
|
||||
# =============================================================================
|
||||
# ЗАПУСК
|
||||
# =============================================================================
|
||||
|
|
|
|||
Loading…
Reference in a new issue