diff --git a/docker/config/nginx/sapl.conf b/docker/config/nginx/sapl.conf index 91b73a94a..12bb24aff 100644 --- a/docker/config/nginx/sapl.conf +++ b/docker/config/nginx/sapl.conf @@ -49,6 +49,10 @@ server { alias /var/interlegis/sapl/collected_static/; } + location /media/CACHE/ { + alias /var/interlegis/sapl/media/CACHE/; + } + location /media/ { internal; alias /var/interlegis/sapl/media/; diff --git a/sapl/base/views.py b/sapl/base/views.py index d9e159fa0..ab9024515 100644 --- a/sapl/base/views.py +++ b/sapl/base/views.py @@ -1513,8 +1513,8 @@ class LogotipoView(RedirectView): def get_redirect_url(self, *args, **kwargs): casa = get_casalegislativa() - logo = casa and casa.logotipo and casa.logotipo.name - return os.path.join(settings.MEDIA_URL, logo) if logo else STATIC_LOGO + url = get_logotipo_url(casa) + return url if url else STATIC_LOGO def filtro_campos(dicionario): @@ -1664,3 +1664,46 @@ def serve_model_file(request, app_label, model_name, pk, field_name): raise Http404 return serve_file(request, file_uuid=meta.uuid) + + +# Image fields served via X-Accel-Redirect — same nginx internal mechanism as +# serve_file but without FileMetadata involvement (images carry no versioning or +# access-control requirement). An explicit allowlist prevents arbitrary ORM +# traversal (RFC §12.3). +IMAGE_FIELDS = frozenset([ + ('base', 'casalegislativa', 'logotipo'), + ('parlamentares', 'partido', 'logo_partido'), + ('parlamentares', 'parlamentar', 'fotografia'), + ('compilacao', 'dispositivo', 'imagem'), +]) + + +def serve_image(request, app_label, model_name, pk, field_name): + """ + Serve an image field via nginx X-Accel-Redirect (RFC §12.4). + + All four image field models are unconditionally public — no permission + check is performed. The allowlist is the only gate. + """ + from django.shortcuts import get_object_or_404 as _get_or_404 + + if (app_label, model_name, field_name) not in IMAGE_FIELDS: + raise Http404 + try: + model = apps.get_model(app_label, model_name) + except LookupError: + raise Http404 + + instance = _get_or_404(model, pk=pk) + field_file = getattr(instance, field_name, None) + if not field_file: + raise Http404 + + response = HttpResponse() + response['X-Accel-Redirect'] = f'/media/{field_file.name}' + return response + + +def get_logotipo_url(casa): + from sapl.utils import get_logotipo_url as _get_logotipo_url + return _get_logotipo_url(casa) diff --git a/sapl/context_processors.py b/sapl/context_processors.py index bded6d7e7..4c903b11e 100644 --- a/sapl/context_processors.py +++ b/sapl/context_processors.py @@ -9,11 +9,13 @@ from sapl.utils import mail_service_configured as mail_service_configured_utils def parliament_info(request): from sapl.base.views import get_casalegislativa + from sapl.utils import get_logotipo_url casa = get_casalegislativa() if casa: - return casa.__dict__ - else: - return {} + ctx = dict(casa.__dict__) + ctx['logotipo_url'] = get_logotipo_url(casa) + return ctx + return {} def mail_service_configured(request): diff --git a/sapl/painel/views.py b/sapl/painel/views.py index cea4e2870..ff95341cc 100644 --- a/sapl/painel/views.py +++ b/sapl/painel/views.py @@ -22,7 +22,7 @@ from sapl.sessao.models import (ExpedienteMateria, OradorExpediente, OrdemDia, PresencaOrdemDia, RegistroVotacao, SessaoPlenaria, SessaoPlenariaPresenca, VotoParlamentar, RegistroLeitura) -from sapl.utils import filiacao_data, get_client_ip, sort_lista_chave +from sapl.utils import filiacao_data, get_client_ip, sort_lista_chave, get_logotipo_url from .models import Cronometro @@ -555,7 +555,7 @@ def get_dados_painel(request, pk): brasao = None if casa and app_config and (bool(casa.logotipo)): - brasao = casa.logotipo.url \ + brasao = get_logotipo_url(casa) \ if app_config.mostrar_brasao_painel else None response = { diff --git a/sapl/relatorios/views.py b/sapl/relatorios/views.py index bc28b3ffc..aa7b0743f 100755 --- a/sapl/relatorios/views.py +++ b/sapl/relatorios/views.py @@ -51,7 +51,7 @@ from sapl.sessao.views import (get_identificacao_basica, get_mesa_diretora, from sapl.settings import MEDIA_URL, RATE_LIMITER_RATE from sapl.settings import STATIC_ROOT from sapl.utils import LISTA_DE_UFS, TrocaTag, filiacao_data, create_barcode, show_results_filter_set, \ - num_materias_por_tipo, parlamentares_ativos, MultiFormatOutputMixin, ratelimit_ip + num_materias_por_tipo, parlamentares_ativos, MultiFormatOutputMixin, ratelimit_ip, get_logotipo_url from .templates import (pdf_capa_processo_gerar, pdf_documento_administrativo_gerar, pdf_espelho_gerar, pdf_etiqueta_protocolo_gerar, pdf_materia_gerar, @@ -1460,8 +1460,8 @@ def resumo_ata_pdf(request, pk): 'decimo_quinto_ordenacao': 'ocorrencias_da_sessao.html', 'decimo_sexto_ordenacao': 'consideracoes_finais.html' }) - header_context = {"casa": casa, - 'logotipo': casa.logotipo, 'MEDIA_URL': MEDIA_URL} + header_context = {"casa": casa, 'logotipo': casa.logotipo, + 'logotipo_url': get_logotipo_url(casa), 'MEDIA_URL': MEDIA_URL} html_template = render_to_string('relatorios/relatorio_ata.html', context) html_header = render_to_string( @@ -1487,6 +1487,7 @@ def cria_relatorio(request, context, html_string, header_info=""): context.update({'rodape': rodape}) header_context = {"casa": casa, 'logotipo': casa.logotipo, + 'logotipo_url': get_logotipo_url(casa), 'MEDIA_URL': MEDIA_URL, 'info': header_info} html_template = render_to_string(html_string, context) @@ -1713,6 +1714,7 @@ def relatorio_sessao_plenaria_pdf(request, pk): html_header = render_to_string('relatorios/header_ata.html', {"casa": casa, "MEDIA_URL": MEDIA_URL, "logotipo": casa.logotipo, + "logotipo_url": get_logotipo_url(casa), "info": info}) pdf_file = make_pdf( @@ -1795,8 +1797,8 @@ def relatorio_materia_tramitacao(request, pk): 'rodape': rodape, 'data': dt.today().strftime('%d/%m/%Y'), 'rodape': rodape}) - header_context = {"casa": casa, - 'logotipo': casa.logotipo, 'MEDIA_URL': MEDIA_URL} + header_context = {"casa": casa, 'logotipo': casa.logotipo, + 'logotipo_url': get_logotipo_url(casa), 'MEDIA_URL': MEDIA_URL} html_template = render_to_string( 'relatorios/relatorio_materia_tramitacao.html', context) diff --git a/sapl/templates/404.html b/sapl/templates/404.html index 82a3dee5e..f2bc5c501 100644 --- a/sapl/templates/404.html +++ b/sapl/templates/404.html @@ -49,7 +49,7 @@