# import standard modules
from fastapi import FastAPI
-from fastapi import Request, Response, HTTPException
+from fastapi import Request, Response
from fastapi.middleware.cors import CORSMiddleware
from fastapi.responses import FileResponse, RedirectResponse
import os
-import ipaddress
# Import local modules
-from backend.security import is_logged_in, require_login
+from backend.security import is_logged_in, require_login, html_protected
from backend.db.hosts import (
get_hosts,
get_host,
)
from backend.routes.health import router as health_router
from backend.routes.login import router as login_router
+from backend.routes.hosts import router as hosts_router
# Import config variables
from backend.config import FRONTEND_DIR, HTTP_PORT
app = FastAPI()
app.include_router(health_router)
app.include_router(login_router)
+app.include_router(hosts_router)
# Allow frontend JS to call the API
app.add_middleware(
def home(request: Request):
return html_protected(request, "hosts.html")
-# Hosts page
-@app.get("/hosts")
-def hosts(request: Request):
- return html_protected(request, "hosts.html")
-
-# Serve hosts.css
-@app.get("/css/hosts.css")
-def css_hosts():
- return FileResponse(os.path.join(FRONTEND_DIR, "css/hosts.css"))
-
# Serve app.js
@app.get("/app.js")
def js():
return FileResponse(os.path.join(FRONTEND_DIR, "app.js"))
-
-# ---------------------------------------------------------
-# API ENDPOINTS
-# ---------------------------------------------------------
-
-@app.get("/api/hosts")
-def api_get_hosts(request: Request):
- require_login(request)
- return get_hosts()
-
-@app.post("/api/hosts")
-def api_add_host(request: Request, data: dict):
- require_login(request)
- name = data.get("name", "").strip()
- ipv4 = data.get("ipv4")
- ipv6 = data.get("ipv6")
- if not name:
- return {"error": "Name is required"}
- if ipv4:
- try:
- ipaddress.IPv4Address(ipv4)
- except:
- return {"error": "Invalid IPv4 format"}
- if ipv6:
- try:
- ipaddress.IPv6Address(ipv6)
- except:
- return {"error": "Invalid IPv6 format"}
- return {"id": add_host(data)}
-
-@app.get("/api/hosts/{host_id}")
-def api_get_host(request: Request, host_id: int):
- require_login(request)
- return get_host(host_id) or {}
-
-@app.put("/api/hosts/{host_id}")
-def api_update_host(request: Request, data: dict, host_id: int):
- require_login(request)
- name = data.get("name", "").strip()
- ipv4 = data.get("ipv4")
- ipv6 = data.get("ipv6")
- if not name:
- return {"error": "Name is required"}
- if ipv4:
- try:
- ipaddress.IPv4Address(ipv4)
- except:
- return {"error": "Invalid IPv4 format"}
- if ipv6:
- try:
- ipaddress.IPv6Address(ipv6)
- except:
- return {"error": "Invalid IPv6 format"}
- update_host(host_id, data)
- return {"status": "ok"}
-
-@app.delete("/api/hosts/{host_id}")
-def api_delete_host(request: Request, host_id: int):
- require_login(request)
- delete_host(host_id)
- return {"status": "ok"}
from fastapi import APIRouter
+# Create Router
router = APIRouter()
+# ---------------------------------------------------------
+# API ENDPOINTS
+# ---------------------------------------------------------
+
@router.get("/health", tags=["health"])
def health_check():
return {"status": "ok"}
--- /dev/null
+# backend/routes/hosts.py
+
+# import standard modules
+from fastapi import APIRouter, Request, Response
+from fastapi.responses import FileResponse, RedirectResponse
+import os
+import ipaddress
+# Import local modules
+from backend.security import is_logged_in, require_login, html_protected
+from backend.db.hosts import (
+ get_hosts,
+ get_host,
+ add_host,
+ update_host,
+ delete_host
+)
+# Import config variables
+from backend.config import FRONTEND_DIR
+
+# Create Router
+router = APIRouter()
+
+# ---------------------------------------------------------
+# FRONTEND PATHS (absolute paths inside Docker)
+# ---------------------------------------------------------
+
+# Hosts page
+@router.get("/hosts")
+def hosts(request: Request):
+ return html_protected(request, "hosts.html")
+
+# Serve hosts.css
+@router.get("/css/hosts.css")
+def css_hosts():
+ return FileResponse(os.path.join(FRONTEND_DIR, "css/hosts.css"))
+
+# ---------------------------------------------------------
+# API ENDPOINTS
+# ---------------------------------------------------------
+
+@router.get("/api/hosts")
+def api_get_hosts(request: Request):
+ require_login(request)
+ return get_hosts()
+
+@router.post("/api/hosts")
+def api_add_host(request: Request, data: dict):
+ require_login(request)
+ name = data.get("name", "").strip()
+ ipv4 = data.get("ipv4")
+ ipv6 = data.get("ipv6")
+ if not name:
+ return {"error": "Name is required"}
+ if ipv4:
+ try:
+ ipaddress.IPv4Address(ipv4)
+ except:
+ return {"error": "Invalid IPv4 format"}
+ if ipv6:
+ try:
+ ipaddress.IPv6Address(ipv6)
+ except:
+ return {"error": "Invalid IPv6 format"}
+ return {"id": add_host(data)}
+
+@router.get("/api/hosts/{host_id}")
+def api_get_host(request: Request, host_id: int):
+ require_login(request)
+ return get_host(host_id) or {}
+
+@router.put("/api/hosts/{host_id}")
+def api_update_host(request: Request, data: dict, host_id: int):
+ require_login(request)
+ name = data.get("name", "").strip()
+ ipv4 = data.get("ipv4")
+ ipv6 = data.get("ipv6")
+ if not name:
+ return {"error": "Name is required"}
+ if ipv4:
+ try:
+ ipaddress.IPv4Address(ipv4)
+ except:
+ return {"error": "Invalid IPv4 format"}
+ if ipv6:
+ try:
+ ipaddress.IPv6Address(ipv6)
+ except:
+ return {"error": "Invalid IPv6 format"}
+ update_host(host_id, data)
+ return {"status": "ok"}
+
+@router.delete("/api/hosts/{host_id}")
+def api_delete_host(request: Request, host_id: int):
+ require_login(request)
+ delete_host(host_id)
+ return {"status": "ok"}
# backend/routes/login.py
# import standard modules
-from fastapi import APIRouter, Request, Response
+from fastapi import APIRouter, Request, Response, HTTPException
from fastapi.responses import FileResponse, RedirectResponse
import os
import time
# Import config variables
from backend.config import FRONTEND_DIR, LOGIN_MAX_ATTEMPTS, LOGIN_WINDOW_SECONDS
+# Create Router
router = APIRouter()
# IP -> lista timestamp tentativi
)
return {"status": "ok"}
- return {"error": "Invalid credentials"}
+ return {"error": "Wrong credentials"}
@router.post("/api/logout")
def api_logout(response: Response):
# backend/security.py
# import standard modules
+import os
from fastapi import Request, HTTPException
+from fastapi.responses import FileResponse, RedirectResponse
from itsdangerous import TimestampSigner
# Import config variables
-from backend.config import SECRET_KEY
+from backend.config import FRONTEND_DIR, SECRET_KEY
signer = TimestampSigner(SECRET_KEY)
+# -----------------------------
+# login check
+# -----------------------------
def is_logged_in(request: Request) -> bool:
token = request.cookies.get("session")
if not token:
except:
return False
+# -----------------------------
+# login check (for api)
+# -----------------------------
def require_login(request: Request):
if not is_logged_in(request):
raise HTTPException(status_code=401, detail="Not authenticated")
+
+# -----------------------------
+# login check (for html)
+# -----------------------------
+def html_protected(request: Request, filename: str):
+ if not is_logged_in(request):
+ return RedirectResponse("/login")
+ return FileResponse(os.path.join(FRONTEND_DIR, filename))
\ No newline at end of file
if (data.status === "ok") {
window.location.href = "/hosts";
} else {
- document.getElementById("loginError").textContent = "Wrong credentials";
+ document.getElementById("loginError").textContent = data.error;
}
}