From 3c0638b02e886b7b5bd63e2681a282276ae94018 Mon Sep 17 00:00:00 2001 From: Edward Oliveira Date: Wed, 17 Sep 2025 20:06:57 -0300 Subject: [PATCH] =?UTF-8?q?Fix=20recibo=20proposi=C3=A7=C3=A3o=20e=20adici?= =?UTF-8?q?ona=20rate=20limiter=20em=20mat=C3=A9ria=20e=20norma?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docker/config/nginx/sapl.conf | 2 +- docker/startup_scripts/gunicorn.conf.py | 3 ++- requirements/requirements.txt | 3 +-- sapl/base/views.py | 2 +- sapl/materia/views.py | 6 +++++- sapl/norma/views.py | 5 +++++ sapl/utils.py | 28 ++++++++++++++----------- 7 files changed, 31 insertions(+), 18 deletions(-) diff --git a/docker/config/nginx/sapl.conf b/docker/config/nginx/sapl.conf index 18641045e..a55731d02 100644 --- a/docker/config/nginx/sapl.conf +++ b/docker/config/nginx/sapl.conf @@ -7,7 +7,7 @@ upstream sapl_server { server { listen 80; - server_name sapl.test; + server_name sapl.prod; client_max_body_size 4G; diff --git a/docker/startup_scripts/gunicorn.conf.py b/docker/startup_scripts/gunicorn.conf.py index 95d2f0256..6bdcacb02 100644 --- a/docker/startup_scripts/gunicorn.conf.py +++ b/docker/startup_scripts/gunicorn.conf.py @@ -52,7 +52,8 @@ graceful_timeout = 30 keepalive = 10 backlog = 2048 max_requests = MAX_REQUESTS -max_requests_jitter = 100 +max_requests_jitter = 200 +worker_max_memory_per_child = 300 * 1024 * 1024 # 300 MB cap # Environment (same as exporting before running) raw_env = [ diff --git a/requirements/requirements.txt b/requirements/requirements.txt index 56c2459b4..aea9f52db 100644 --- a/requirements/requirements.txt +++ b/requirements/requirements.txt @@ -22,8 +22,7 @@ pytz==2019.3 python-magic==0.4.15 unipath==1.1 Pillow==10.3.0 -rlPyCairo==0.3.0 -reportlab==4.2.0 +reportlab==3.6.13 WeasyPrint==66 trml2pdf==0.6 gunicorn==23.0.0 diff --git a/sapl/base/views.py b/sapl/base/views.py index ce3a0a717..7c935d421 100644 --- a/sapl/base/views.py +++ b/sapl/base/views.py @@ -68,7 +68,7 @@ class IndexView(TemplateView): @method_decorator(ratelimit(key=lambda group, request: get_client_ip(request), - rate='20/m', + rate='10/m', method=ratelimit.UNSAFE, block=True), name='dispatch') class LoginSapl(views.LoginView): diff --git a/sapl/materia/views.py b/sapl/materia/views.py index f64d8134b..5a05149da 100644 --- a/sapl/materia/views.py +++ b/sapl/materia/views.py @@ -24,7 +24,6 @@ from django.shortcuts import render from django.template import loader from django.urls import reverse from django.utils import formats, timezone -from django.utils.encoding import force_text from django.utils.translation import ugettext_lazy as _ from django.views.generic import CreateView, ListView, TemplateView, UpdateView from django.views.generic.base import RedirectView @@ -32,6 +31,9 @@ from django.views.generic.edit import FormView from django_filters.views import FilterView import weasyprint +from ratelimit.decorators import ratelimit +from django.utils.decorators import method_decorator + import sapl from sapl.base.email_utils import do_envia_email_confirmacao from sapl.base.models import Autor, CasaLegislativa, AppConfig as BaseAppConfig @@ -1908,6 +1910,7 @@ class MateriaLegislativaCrud(Crud): def get_success_url(self): return self.search_url + @method_decorator(ratelimit(key='ip', rate='10/m', block=True), name='dispatch') class DetailView(Crud.DetailView): layout_key = 'MateriaLegislativaDetail' @@ -1920,6 +1923,7 @@ class MateriaLegislativaCrud(Crud): pk=self.kwargs['pk']) return context + @method_decorator(ratelimit(key='ip', rate='10/m', block=True), name='dispatch') class ListView(Crud.ListView, RedirectView): def get_redirect_url(self, *args, **kwargs): diff --git a/sapl/norma/views.py b/sapl/norma/views.py index 27758a1ca..bcd059805 100644 --- a/sapl/norma/views.py +++ b/sapl/norma/views.py @@ -19,6 +19,9 @@ from django.views.generic.edit import FormView from django_filters.views import FilterView import weasyprint +from ratelimit.decorators import ratelimit +from django.utils.decorators import method_decorator + from sapl import settings import sapl from sapl.base.models import AppConfig @@ -280,6 +283,7 @@ class NormaCrud(Crud): namespace = self.model._meta.app_config.name return reverse('%s:%s' % (namespace, 'norma_pesquisa')) + @method_decorator(ratelimit(key='ip', rate='10/m', block=True), name='dispatch') class DetailView(Crud.DetailView): def get(self, request, *args, **kwargs): estatisticas_acesso_normas = AppConfig.objects.first().estatisticas_acesso_normas @@ -337,6 +341,7 @@ class NormaCrud(Crud): layout_key = 'NormaJuridicaCreate' + @method_decorator(ratelimit(key='ip', rate='10/m', block=True), name='dispatch') class ListView(Crud.ListView): def get(self, request, *args, **kwargs): diff --git a/sapl/utils.py b/sapl/utils.py index 9d6399c5e..6554c5aea 100644 --- a/sapl/utils.py +++ b/sapl/utils.py @@ -419,21 +419,25 @@ def get_base_url(request): return "{0}://{1}".format(protocol, current_domain) -def create_barcode(value, width=170, height=50): - ''' - creates a base64 encoded barcode PNG image - ''' +def create_barcode(value, width=170, height=50, dpi=72): + """ + creates a base64 encoded barcode PNG image + """ from base64 import b64encode from reportlab.graphics.barcode import createBarcodeDrawing + value_bytes = bytes(value, "ascii") - barcode = createBarcodeDrawing('Code128', - value=value_bytes, - barWidth=width, - height=height, - fontSize=2, - humanReadable=True) - data = b64encode(barcode.asString('png')) - return data.decode('utf-8') + barcode = createBarcodeDrawing( + 'Code128', + value=value_bytes, + barWidth=width, + height=height, + fontSize=2, + humanReadable=True + ) + # Lower DPI prevents Cairo surface from blowing up + png_bytes = barcode.asString("png", dpi=dpi) + return b64encode(png_bytes).decode("utf-8") YES_NO_CHOICES = [(True, _('Sim')), (False, _('Não'))]