From 789d0100f127879f2256ad5ced9bb3f04c03437e Mon Sep 17 00:00:00 2001 From: Alexander Myasoedov Date: Sat, 30 Nov 2024 09:38:48 +0200 Subject: [PATCH] feat(add templates): --- agentic_security/routes/static.py | 85 ++++++++-- agentic_security/static/index.html | 150 +----------------- agentic_security/static/main.js | 1 + agentic_security/static/partials/concent.html | 67 ++++++++ agentic_security/static/partials/footer.html | 41 +++++ agentic_security/static/partials/head.html | 41 +++++ 6 files changed, 226 insertions(+), 159 deletions(-) create mode 100644 agentic_security/static/partials/concent.html create mode 100644 agentic_security/static/partials/footer.html create mode 100644 agentic_security/static/partials/head.html diff --git a/agentic_security/routes/static.py b/agentic_security/routes/static.py index 3f01eb8..0fea2ce 100644 --- a/agentic_security/routes/static.py +++ b/agentic_security/routes/static.py @@ -1,34 +1,85 @@ from pathlib import Path +from typing import Optional -from fastapi import APIRouter -from fastapi.responses import FileResponse +from fastapi import APIRouter, HTTPException, Request +from fastapi.responses import FileResponse, HTMLResponse +from fastapi.templating import Jinja2Templates +from jinja2 import Environment, FileSystemLoader +from starlette.responses import Response from ..models.schemas import Settings router = APIRouter() +STATIC_DIR = Path(__file__).parent.parent / "static" + +# Configure templates with custom delimiters to avoid conflicts +templates = Jinja2Templates(directory=str(STATIC_DIR)) +templates.env = Environment( + loader=FileSystemLoader(str(STATIC_DIR)), + autoescape=True, + block_start_string="[[%", + block_end_string="%]]", + variable_start_string="[[", + variable_end_string="]]", +) + +# Content type mapping for static files +CONTENT_TYPES = { + ".js": "application/javascript", + ".ico": "image/x-icon", + ".html": "text/html", + ".css": "text/css", +} -@router.get("/") -async def root(): - agentic_security_path = Path(__file__).parent.parent - return FileResponse(f"{agentic_security_path}/static/index.html") +def get_static_file(filepath: Path, content_type: Optional[str] = None) -> FileResponse: + """ + Helper function to serve static files with proper error handling and caching. + + Args: + filepath: Path to the static file + content_type: Optional content type override + + Returns: + FileResponse with appropriate headers + + Raises: + HTTPException if file not found + """ + if not filepath.is_file(): + raise HTTPException(status_code=404, detail="File not found") + + headers = { + "Cache-Control": "public, max-age=3600", + "Content-Type": content_type + or CONTENT_TYPES.get(filepath.suffix, "application/octet-stream"), + } + + return FileResponse(filepath, headers=headers) + + +@router.get("/", response_class=HTMLResponse) +async def root(request: Request) -> Response: + """Serve the main index.html template.""" + return templates.TemplateResponse("index.html", {"request": request}) @router.get("/main.js") -async def main_js(): - agentic_security_path = Path(__file__).parent.parent - return FileResponse(f"{agentic_security_path}/static/main.js") +async def main_js() -> FileResponse: + """Serve the main JavaScript file.""" + return get_static_file(STATIC_DIR / "main.js") @router.get("/telemetry.js") -async def telemetry_js(): - agentic_security_path = Path(__file__).parent.parent - if Settings.DISABLE_TELEMETRY: - return FileResponse(f"{agentic_security_path}/static/telemetry_disabled.js") - return FileResponse(f"{agentic_security_path}/static/telemetry.js") +async def telemetry_js() -> FileResponse: + """ + Serve either telemetry.js or telemetry_disabled.js based on settings. + """ + filename = "telemetry_disabled.js" if Settings.DISABLE_TELEMETRY else "telemetry.js" + return get_static_file(STATIC_DIR / filename) @router.get("/favicon.ico") -async def favicon(): - agentic_security_path = Path(__file__).parent.parent - return FileResponse(f"{agentic_security_path}/static/favicon.ico") +async def favicon() -> FileResponse: + """Serve the favicon.""" + return get_static_file(STATIC_DIR / "favicon.ico") diff --git a/agentic_security/static/index.html b/agentic_security/static/index.html index 1565604..0630be5 100644 --- a/agentic_security/static/index.html +++ b/agentic_security/static/index.html @@ -1,46 +1,9 @@ - - - - LLM Vulnerability Scanner - - - - - - - + [[% block head %]] + [[% include "partials/head.html" %]] + [[% endblock head %]] +
@@ -68,68 +31,7 @@
- + [[% include "partials/concent.html" %]]
@@ -503,46 +405,10 @@
- - + [[% block footer %]] + [[% include "partials/footer.html" %]] + [[% endblock footer %]] diff --git a/agentic_security/static/main.js b/agentic_security/static/main.js index 2e55f55..ae5a61c 100644 --- a/agentic_security/static/main.js +++ b/agentic_security/static/main.js @@ -3,6 +3,7 @@ let URL = window.location.href; if (URL.endsWith('/')) { URL = URL.slice(0, -1); } +URL = URL.replace('/#', ''); // Vue application let LLM_SPECS = [ diff --git a/agentic_security/static/partials/concent.html b/agentic_security/static/partials/concent.html new file mode 100644 index 0000000..5f93895 --- /dev/null +++ b/agentic_security/static/partials/concent.html @@ -0,0 +1,67 @@ + diff --git a/agentic_security/static/partials/footer.html b/agentic_security/static/partials/footer.html new file mode 100644 index 0000000..0d1acf8 --- /dev/null +++ b/agentic_security/static/partials/footer.html @@ -0,0 +1,41 @@ + + diff --git a/agentic_security/static/partials/head.html b/agentic_security/static/partials/head.html new file mode 100644 index 0000000..e1ffc9b --- /dev/null +++ b/agentic_security/static/partials/head.html @@ -0,0 +1,41 @@ + + + + LLM Vulnerability Scanner + + + + + + +