🔒 Implementação de segurança: Login Web fixo e proteção de API
This commit is contained in:
64
main.py
64
main.py
@@ -1,11 +1,16 @@
|
||||
import os
|
||||
import psutil
|
||||
from fastapi import FastAPI, Request
|
||||
import subprocess
|
||||
import time
|
||||
import json
|
||||
from fastapi import FastAPI, Request, Header, Depends, HTTPException, status
|
||||
from fastapi.responses import HTMLResponse, JSONResponse
|
||||
from fastapi.staticfiles import StaticFiles
|
||||
from fastapi.templating import Jinja2Templates
|
||||
from dotenv import load_dotenv
|
||||
from starlette.concurrency import run_in_threadpool
|
||||
|
||||
from ai_agent import query_agent
|
||||
from config import get_config, save_config
|
||||
|
||||
# Carrega as variáveis do .env
|
||||
load_dotenv()
|
||||
@@ -13,22 +18,37 @@ load_dotenv()
|
||||
app = FastAPI(title="VpsTelegramBot API")
|
||||
|
||||
# Configura templates HTML
|
||||
# Certifique-se de que a pasta 'templates' existe e tem o index.html
|
||||
templates = Jinja2Templates(directory="templates")
|
||||
|
||||
@app.get("/favicon.ico", include_in_schema=False)
|
||||
async def favicon():
|
||||
return JSONResponse(content={"status": "ok"})
|
||||
# --- SEGURANÇA ---
|
||||
async def verify_password(x_web_password: str = Header(None)):
|
||||
cfg = get_config()
|
||||
saved_pwd = cfg.get("web_password", "@@Gi05Br;;")
|
||||
if not x_web_password or x_web_password != saved_pwd:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_401_UNAUTHORIZED,
|
||||
detail="Senha Web inválida ou ausente."
|
||||
)
|
||||
return True
|
||||
|
||||
# --- ROTAS PÚBLICAS ---
|
||||
@app.get("/", response_class=HTMLResponse)
|
||||
async def read_root(request: Request):
|
||||
"""Renderiza o Dashboard Web."""
|
||||
return templates.TemplateResponse("index.html", {"request": request})
|
||||
|
||||
from starlette.concurrency import run_in_threadpool
|
||||
@app.get("/favicon.ico", include_in_schema=False)
|
||||
async def favicon():
|
||||
"""Favicon dummy para evitar 404."""
|
||||
return JSONResponse(content={"status": "ok"})
|
||||
|
||||
# --- ROTAS PROTEGIDAS (API) ---
|
||||
@app.get("/api/login")
|
||||
async def check_login(is_auth: bool = Depends(verify_password)):
|
||||
return {"status": "success"}
|
||||
|
||||
@app.get("/api/status")
|
||||
async def get_system_status():
|
||||
async def get_system_status(is_auth: bool = Depends(verify_password)):
|
||||
"""Retorna o status do sistema (CPU, RAM, Disco) sem travar o loop."""
|
||||
def get_stats():
|
||||
cpu_percent = psutil.cpu_percent(interval=0.1)
|
||||
@@ -47,24 +67,20 @@ async def get_system_status():
|
||||
"percent": disk.percent
|
||||
}
|
||||
}
|
||||
|
||||
data = await run_in_threadpool(get_stats)
|
||||
return JSONResponse(content=data)
|
||||
|
||||
import subprocess
|
||||
from config import get_config, save_config
|
||||
|
||||
@app.get("/api/config")
|
||||
async def read_configuration():
|
||||
async def read_configuration(is_auth: bool = Depends(verify_password)):
|
||||
return JSONResponse(content=get_config())
|
||||
|
||||
@app.post("/api/config")
|
||||
async def update_configuration(req: dict):
|
||||
async def update_configuration(req: dict, is_auth: bool = Depends(verify_password)):
|
||||
save_config(req)
|
||||
return JSONResponse(content={"status": "success"})
|
||||
|
||||
@app.post("/api/action")
|
||||
async def execute_smart_action(action: dict):
|
||||
async def execute_smart_action(action: dict, is_auth: bool = Depends(verify_password)):
|
||||
"""Executa ações predefinidas no servidor (Smart Actions da Web UI)."""
|
||||
action_type = action.get("type")
|
||||
|
||||
@@ -72,37 +88,31 @@ async def execute_smart_action(action: dict):
|
||||
return JSONResponse(content={"status": "success", "message": "Pong! Servidor online e responsivo."})
|
||||
|
||||
elif action_type == "restart_bot":
|
||||
# Dá um pequeno delay e depois reinicia o próprio container a partir de fora (pelo host docker)
|
||||
subprocess.Popen("sleep 1 && docker restart vps-ai-agent", shell=True)
|
||||
return JSONResponse(content={"status": "success", "message": "Reboot do Agente autorizado. Estará de volta em instantes!"})
|
||||
return JSONResponse(content={"status": "success", "message": "Reboot do Agente autorizado."})
|
||||
|
||||
elif action_type == "clear_cache":
|
||||
# Roda um docker prune para deletar volumes perdidos e todos containers parados (limpeza profunda)
|
||||
subprocess.Popen("docker system prune -af --volumes", shell=True)
|
||||
return JSONResponse(content={"status": "success", "message": "Limpando caches obsoletos em background! Verifique o gráfico de disco em instantes."})
|
||||
return JSONResponse(content={"status": "success", "message": "Limpando caches obsoletos em background!"})
|
||||
|
||||
elif action_type == "reboot_vps":
|
||||
# Hacker trick: Roda um container hiper-privilegiado descartável pra entrar no espaço do host (PID 1) e emitir comando de REBOOT físico
|
||||
subprocess.Popen("sleep 2 && docker run --rm --privileged --pid=host alpine nsenter -t 1 -m -u -n -i reboot", shell=True)
|
||||
return JSONResponse(content={"status": "success", "message": "🚨 O REBOOT CRÍTICO COMEÇOU. A VPS inteira desligará e religará agora."})
|
||||
return JSONResponse(content={"status": "success", "message": "🚨 O REBOOT CRÍTICO COMEÇOU."})
|
||||
|
||||
return JSONResponse(content={"status": "error", "message": "Ação desconhecida."}, status_code=400)
|
||||
|
||||
@app.post("/api/chat")
|
||||
async def web_chat(message: dict):
|
||||
async def web_chat(message: dict, is_auth: bool = Depends(verify_password)):
|
||||
"""Endpoint para interagir com a IA via Web UI."""
|
||||
user_text = message.get("text", "")
|
||||
if not user_text:
|
||||
return JSONResponse(content={"reply": "Por favor, digite um comando válido."})
|
||||
|
||||
# Executa a IA em uma thread separada para não travar a UI/API de status
|
||||
reply = await run_in_threadpool(query_agent, prompt=user_text)
|
||||
return JSONResponse(content={"reply": reply})
|
||||
|
||||
import time
|
||||
|
||||
@app.get("/api/test_llm")
|
||||
async def test_llm_speed():
|
||||
async def test_llm_speed(is_auth: bool = Depends(verify_password)):
|
||||
"""Mede a velocidade de resposta da IA ativa."""
|
||||
start_time = time.time()
|
||||
try:
|
||||
@@ -116,11 +126,9 @@ async def test_llm_speed():
|
||||
async def telegram_webhook(request: Request):
|
||||
"""Recebe as atualizações (mensagens) do Telegram."""
|
||||
update = await request.json()
|
||||
# O bot_logic.py lidará com o 'update' no futuro
|
||||
print("Update recebido do Telegram:", update)
|
||||
return {"ok": True}
|
||||
|
||||
if __name__ == "__main__":
|
||||
import uvicorn
|
||||
# Executa o servidor na porta 8000 acessível de qualquer lugar na rede
|
||||
uvicorn.run("main:app", host="0.0.0.0", port=8000, reload=True)
|
||||
|
||||
Reference in New Issue
Block a user