from __future__ import annotations import os from pathlib import Path from flask import Blueprint, abort, current_app, send_from_directory from app.services.vault import Vault bp = Blueprint("attachments", __name__, url_prefix="/attachments") @bp.get("/") def serve_attachment(subpath: str): # Resolve within the vault attachments directory vault_path = current_app.config.get("KB_VAULT_PATH") if not vault_path: abort(404) v = Vault(vault_path) attachments_dir = Path(v.paths.attachments).resolve() requested = (attachments_dir / subpath).resolve() # Prevent path traversal try: requested.relative_to(attachments_dir) except Exception: abort(403) if not requested.exists() or not requested.is_file(): abort(404) return send_from_directory(attachments_dir, os.path.relpath(str(requested), str(attachments_dir)))