From 76bbc71fc6ebbe04660fa33a8bab1c2f40e61777 Mon Sep 17 00:00:00 2001 From: Kenio de Souza Date: Wed, 12 Nov 2025 17:00:35 -0300 Subject: [PATCH] =?UTF-8?q?fix():=20Ajustado=20endpoint=20de=20visualiza?= =?UTF-8?q?=C3=A7=C3=A3o=20de=20arquivo?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../endpoints/atos_view_document_endpoint.py | 45 +++++++++++++------ 1 file changed, 32 insertions(+), 13 deletions(-) diff --git a/packages/v1/administrativo/endpoints/atos_view_document_endpoint.py b/packages/v1/administrativo/endpoints/atos_view_document_endpoint.py index b86b735..1351c2b 100644 --- a/packages/v1/administrativo/endpoints/atos_view_document_endpoint.py +++ b/packages/v1/administrativo/endpoints/atos_view_document_endpoint.py @@ -1,7 +1,8 @@ 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 datetime import datetime, timedelta +from database.mysql import get_database_settings from pathlib import Path router = APIRouter() @@ -15,31 +16,49 @@ ALGORITHM = "HS256" STORAGE_DIR = Path("storage") -@router.get("/{file_id}/{file_path:path}") -def visualizar_arquivo(file_id: str, file_path: str, token: str = Query(...)): +@router.get("/{hash}/{file_path:path}") +def visualizar_arquivo(hash: 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 + Valida o token JWT e retorna o arquivo PDF, se autorizado. + URL esperada: + /view//?token= + Exemplo real: + /view/d7e8f9g0h1i2/100/57/documento.pdf?token=xxxxx """ - - # --- 1. Valida token JWT --- try: + # Decodifica o token usando a chave e algoritmo definidos payload = jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM]) - if payload["sub"] != file_id or payload["filename"] != file_path: - raise HTTPException(status_code=403, detail="Token inválido.") + + # Extrai os campos esperados do token + faixa_superior = payload.get("faixa_superior") + ato_id = payload.get("ato_id") + file_name = payload.get("file_name") + + # Se algum campo essencial estiver faltando → token inválido + if not all([faixa_superior, ato_id, file_name]): + raise HTTPException(status_code=400, detail="Token malformado.") + + # Reconstrói o caminho esperado a partir do token + expected_path = f"{faixa_superior}/{ato_id}/{file_name}" + + # Se o caminho do arquivo solicitado não bate com o token → bloqueia + if expected_path != file_path: + raise HTTPException( + status_code=403, detail="Token não corresponde ao arquivo." + ) + except JWTError: raise HTTPException(status_code=401, detail="Token expirado ou inválido.") - # --- 2. Monta caminho real no disco --- + # Monta o caminho físico 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.") + # Retorna o arquivo inline (abre no navegador) return FileResponse( full_path, media_type="application/pdf", - headers={"Content-Disposition": "inline"}, # abre no navegador + headers={"Content-Disposition": "inline"}, )