133 lines
4.3 KiB
Python
133 lines
4.3 KiB
Python
|
|
from fastapi import FastAPI, HTTPException
|
|
from pydantic import BaseModel
|
|
from fastapi.staticfiles import StaticFiles
|
|
from fastapi.responses import HTMLResponse
|
|
from fastapi.middleware.cors import CORSMiddleware
|
|
from typing import Optional, Dict, Any
|
|
import uvicorn
|
|
from callback import call_action
|
|
from fastapi.responses import JSONResponse
|
|
import hashlib
|
|
import json
|
|
import time
|
|
import yaml
|
|
from pathlib import Path
|
|
from utils.get_primary_ip import get_primary_ip
|
|
import os
|
|
from dotenv import dotenv_values
|
|
|
|
config = dotenv_values(".env")
|
|
PASSWORD = config.get("PASSWORD")
|
|
SKIP_HASH = False
|
|
|
|
app = FastAPI()
|
|
|
|
# Add CORS middleware
|
|
app.add_middleware(
|
|
CORSMiddleware,
|
|
allow_origins=["*"], # Allows all origins
|
|
allow_credentials=True,
|
|
allow_methods=["*"], # Allows all methods (GET, POST, etc.)
|
|
allow_headers=["*"], # Allows all headers
|
|
)
|
|
|
|
# Static files & UI server
|
|
app.mount("/assets", StaticFiles(directory="static/frontend/dist/assets"), name="assets")
|
|
app.mount("/icons", StaticFiles(directory="static/frontend/public/icons"), name="icons")
|
|
|
|
# Show main page
|
|
@app.get("/")
|
|
async def read_index():
|
|
with open("static/frontend/dist/index.html", "r", encoding="utf-8") as f:
|
|
html_content = f.read()
|
|
return HTMLResponse(content=html_content, status_code=200)
|
|
|
|
# Pydantic model for request payload
|
|
class CommandModel(BaseModel):
|
|
args: Dict[str, Any]
|
|
hash: str # Mandatory hash field
|
|
|
|
@app.get("/primary-ip", response_model=None)
|
|
def get_config():
|
|
return get_primary_ip()
|
|
|
|
@app.get("/frontend-config", response_model=None)
|
|
def get_config(hash: str):
|
|
|
|
computed_hash = hashlib.sha256( ("frontend_config"+PASSWORD).encode("utf-8")).hexdigest()
|
|
|
|
# Verify hash
|
|
if computed_hash != hash:
|
|
raise HTTPException(status_code=401, detail="Invalid hash")
|
|
|
|
CONFIG_FILE = Path("config/frontend.yaml")
|
|
|
|
# Checking the existence of the file
|
|
if not CONFIG_FILE.exists():
|
|
raise HTTPException(status_code=404, detail="Файл frontend.yaml не найден")
|
|
|
|
try:
|
|
# YAML reading and parsing
|
|
with open(CONFIG_FILE, "r", encoding="utf-8") as file:
|
|
data = yaml.safe_load(file)
|
|
|
|
# Adding an id
|
|
for idx, item in enumerate(data):
|
|
item["id"] = idx
|
|
|
|
return data
|
|
|
|
except yaml.YAMLError as e:
|
|
# YAML parsing error
|
|
raise HTTPException(status_code=500, detail=f"Ошибка в формате YAML: {e}")
|
|
|
|
except Exception as e:
|
|
# Any other error
|
|
raise HTTPException(status_code=500, detail=f"Внутренняя ошибка сервера: {e}")
|
|
|
|
|
|
|
|
# Process actions via POST
|
|
@app.post("/action/{name:path}")
|
|
async def handle_action(name: str, payload: CommandModel):
|
|
|
|
action_args = payload.args
|
|
hash_with_ts = payload.hash
|
|
if(not SKIP_HASH):
|
|
if not hash_with_ts:
|
|
raise HTTPException(status_code=400, detail="Missing hash")
|
|
|
|
# Split hash and timestamp
|
|
try:
|
|
received_hash, received_ts = hash_with_ts.split(".")
|
|
received_ts = int(received_ts)
|
|
except ValueError:
|
|
raise HTTPException(status_code=400, detail="Invalid hash format")
|
|
|
|
# Check if token is within 5-second window
|
|
current_ts = int(time.time())
|
|
if abs(current_ts - received_ts) > 5:
|
|
raise HTTPException(status_code=401, detail="Token expired")
|
|
|
|
# Reconstruct hash
|
|
data_to_hash = PASSWORD + json.dumps(action_args, separators=(",", ":")) + str(received_ts)
|
|
computed_hash = hashlib.sha256(data_to_hash.encode("utf-8")).hexdigest()
|
|
|
|
# Verify hash
|
|
if computed_hash != received_hash:
|
|
raise HTTPException(status_code=401, detail="Invalid hash")
|
|
|
|
try:
|
|
# Вызываем функцию из callback.py, передавая имя действия и аргументы
|
|
result = await call_action(name, action_args or {})
|
|
return JSONResponse(content={"status": "success", "result": result, "command": name})
|
|
except ValueError as e:
|
|
# Если функция не найдена, возвращаем 404
|
|
raise HTTPException(status_code=404, detail=str(e))
|
|
except Exception as e:
|
|
# Обработка остальных ошибок
|
|
raise HTTPException(status_code=500, detail=f"Internal server error: {str(e)}")
|
|
|
|
|
|
uvicorn.run(app, host="0.0.0.0", port=8000) |