From 73dd1ac3bd2d7fd194b73d88d0b33993ee3366a7 Mon Sep 17 00:00:00 2001 From: Kenio de Souza Date: Wed, 12 Nov 2025 16:11:44 -0300 Subject: [PATCH] feat(): Criado url protegida por token, acesso via endpoint --- actions/validations/hash.py | 17 +++++++- .../endpoints/atos_view_document_endpoint.py | 39 +++++++++++++++---- .../ato_principal_show_atos_repository.py | 4 -- 3 files changed, 46 insertions(+), 14 deletions(-) diff --git a/actions/validations/hash.py b/actions/validations/hash.py index 0d45dfb..e3d2bba 100644 --- a/actions/validations/hash.py +++ b/actions/validations/hash.py @@ -31,9 +31,22 @@ def generate_storage_hash() -> str: # Função que gera o token temporário para acesso ao documento +# def generate_temporary_token( +# expires_minutes: int, +# secret_key: str, +# algorithm: str, +# ) -> str: +# """Gera um token JWT válido por poucos minutos.""" +# expire = datetime.utcnow() + timedelta(minutes=expires_minutes) +# payload = { +# "exp": expire, +# } +# return jwt.encode(payload, secret_key, algorithm=algorithm) + + def generate_temporary_token( file_id: str, - filename: str, + file_path: str, expires_minutes: int, secret_key: str, algorithm: str, @@ -42,7 +55,7 @@ def generate_temporary_token( expire = datetime.utcnow() + timedelta(minutes=expires_minutes) payload = { "sub": file_id, - "filename": filename, + "filename": file_path, # caminho relativo completo "exp": expire, } return jwt.encode(payload, secret_key, algorithm=algorithm) diff --git a/packages/v1/administrativo/endpoints/atos_view_document_endpoint.py b/packages/v1/administrativo/endpoints/atos_view_document_endpoint.py index 0a963a8..b86b735 100644 --- a/packages/v1/administrativo/endpoints/atos_view_document_endpoint.py +++ b/packages/v1/administrativo/endpoints/atos_view_document_endpoint.py @@ -1,22 +1,45 @@ from fastapi import APIRouter, Query, HTTPException from fastapi.responses import FileResponse from jose import jwt, JWTError +from database.mysql import SessionLocal, get_database_settings +from pathlib import Path router = APIRouter() +# === Configuração do token temporário === +DB_SETTINGS = get_database_settings() +SECRET_KEY = getattr(DB_SETTINGS, "aeskey", None) +ALGORITHM = "HS256" -@router.get("/{file_id}/{filename}") -def visualizar_arquivo(file_id: str, filename: str, token: str = Query(...)): - """Valida o token e retorna o arquivo se autorizado.""" +# Pasta base onde os arquivos são armazenados +STORAGE_DIR = Path("storage") + + +@router.get("/{file_id}/{file_path:path}") +def visualizar_arquivo(file_id: str, file_path: str, token: str = Query(...)): + """ + Valida o token e retorna o arquivo do storage, se autorizado. + Exemplo de URL: + /view/d7e8f9g0h1i2/100/57/documento.pdf?token=xxxx + """ + + # --- 1. Valida token JWT --- try: payload = jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM]) - if payload["sub"] != file_id or payload["filename"] != filename: + if payload["sub"] != file_id or payload["filename"] != file_path: raise HTTPException(status_code=403, detail="Token inválido.") except JWTError: raise HTTPException(status_code=401, detail="Token expirado ou inválido.") - file_path = f"files/{filename}" - try: - return FileResponse(file_path, media_type="application/pdf") - except FileNotFoundError: + # --- 2. Monta caminho real no disco --- + full_path = STORAGE_DIR / file_path + + # --- 3. Retorna arquivo, se existir --- + if not full_path.exists(): raise HTTPException(status_code=404, detail="Arquivo não encontrado.") + + return FileResponse( + full_path, + media_type="application/pdf", + headers={"Content-Disposition": "inline"}, # abre no navegador + ) diff --git a/packages/v1/administrativo/repositories/ato_principal/ato_principal_show_atos_repository.py b/packages/v1/administrativo/repositories/ato_principal/ato_principal_show_atos_repository.py index 04a7039..5d706a4 100644 --- a/packages/v1/administrativo/repositories/ato_principal/ato_principal_show_atos_repository.py +++ b/packages/v1/administrativo/repositories/ato_principal/ato_principal_show_atos_repository.py @@ -117,8 +117,6 @@ class ShowAtosRepository: "url": ( f"{URL_API}/view/{generate_storage_hash()}/{d.url.decode('utf-8')}?token=" + generate_temporary_token( - generate_storage_hash(), - d.url.decode("utf-8"), 10, SECRET_KEY, ALGORITHM, @@ -188,8 +186,6 @@ class ShowAtosRepository: "url": ( f"{URL_API}/view/{generate_storage_hash()}/{d.url.decode('utf-8')}?token=" + generate_temporary_token( - generate_storage_hash(), - d.url.decode("utf-8"), 10, SECRET_KEY, ALGORITHM,