From 12cb253e58f987821d93348fad31c077c46ee74d Mon Sep 17 00:00:00 2001 From: Edward Oliveira Date: Mon, 22 Sep 2025 17:04:24 -0300 Subject: [PATCH] Hot-fix: rate limiter get_ip --- sapl/base/views.py | 7 ++++--- sapl/materia/views.py | 27 +++++++++++++++++++++------ sapl/norma/views.py | 24 ++++++++++++++++++------ sapl/sessao/views.py | 14 ++++++++++---- sapl/utils.py | 12 ++++++++++-- 5 files changed, 63 insertions(+), 21 deletions(-) diff --git a/sapl/base/views.py b/sapl/base/views.py index 7c935d421..68493dc04 100644 --- a/sapl/base/views.py +++ b/sapl/base/views.py @@ -51,7 +51,7 @@ from sapl.sessao.models import (Bancada, SessaoPlenaria) from sapl.settings import EMAIL_SEND_USER from sapl.utils import (gerar_hash_arquivo, intervalos_tem_intersecao, mail_service_configured, SEPARADOR_HASH_PROPOSICAO, show_results_filter_set, google_recaptcha_configured, - get_client_ip, sapn_is_enabled, is_weak_password) + get_client_ip, sapn_is_enabled, is_weak_password, ratelimit_ip) from .forms import (AlterarSenhaForm, CasaLegislativaForm, ConfiguracoesAppForm, EstatisticasAcessoNormasForm) from .models import AppConfig, CasaLegislativa @@ -67,10 +67,11 @@ class IndexView(TemplateView): return TemplateView.get(self, request, *args, **kwargs) -@method_decorator(ratelimit(key=lambda group, request: get_client_ip(request), +@method_decorator(ratelimit(key=ratelimit_ip, rate='10/m', method=ratelimit.UNSAFE, - block=True), name='dispatch') + block=True), + name='dispatch') class LoginSapl(views.LoginView): template_name = 'base/login.html' authentication_form = LoginForm diff --git a/sapl/materia/views.py b/sapl/materia/views.py index ce158228b..cfd9306c5 100644 --- a/sapl/materia/views.py +++ b/sapl/materia/views.py @@ -56,7 +56,7 @@ from sapl.utils import (autor_label, autor_modal, gerar_hash_arquivo, get_base_u get_client_ip, get_mime_type_from_file_extension, lista_anexados, mail_service_configured, montar_row_autor, SEPARADOR_HASH_PROPOSICAO, show_results_filter_set, get_tempfile_dir, - google_recaptcha_configured, MultiFormatOutputMixin) + google_recaptcha_configured, MultiFormatOutputMixin, ratelimit_ip) from .forms import (AcessorioEmLoteFilterSet, AcompanhamentoMateriaForm, AnexadaEmLoteFilterSet, AdicionarVariasAutoriasFilterSet, @@ -1461,7 +1461,10 @@ class TramitacaoCrud(MasterDetailCrud): return initial - @method_decorator(ratelimit(key='ip', rate='10/m', block=True), name='dispatch') + @method_decorator(ratelimit(key=ratelimit_ip, + rate='10/m', + block=True), + name='dispatch') class ListView(MasterDetailCrud.ListView): def get_queryset(self): @@ -1534,7 +1537,10 @@ class TramitacaoCrud(MasterDetailCrud): return HttpResponseRedirect(url) - @method_decorator(ratelimit(key='ip', rate='10/m', block=True), name='dispatch') + @method_decorator(ratelimit(key=ratelimit_ip, + rate='10/m', + block=True), + name='dispatch') class DetailView(MasterDetailCrud.DetailView): template_name = "materia/tramitacao_detail.html" @@ -1912,7 +1918,10 @@ class MateriaLegislativaCrud(Crud): def get_success_url(self): return self.search_url - @method_decorator(ratelimit(key='ip', rate='10/m', block=True), name='dispatch') + @method_decorator(ratelimit(key=ratelimit_ip, + rate='10/m', + block=True), + name='dispatch') class DetailView(Crud.DetailView): layout_key = 'MateriaLegislativaDetail' @@ -1925,7 +1934,10 @@ class MateriaLegislativaCrud(Crud): pk=self.kwargs['pk']) return context - @method_decorator(ratelimit(key='ip', rate='10/m', block=True), name='dispatch') + @method_decorator(ratelimit(key=ratelimit_ip, + rate='10/m', + block=True), + name='dispatch') class ListView(Crud.ListView, RedirectView): def get_redirect_url(self, *args, **kwargs): @@ -2046,7 +2058,10 @@ class AcompanhamentoExcluirView(TemplateView): return HttpResponseRedirect(self.get_success_url()) -@method_decorator(ratelimit(key='ip', rate='10/m', block=True), name='dispatch') +@method_decorator(ratelimit(key=ratelimit_ip, + rate='10/m', + block=True), + name='dispatch') class MateriaLegislativaPesquisaView(MultiFormatOutputMixin, FilterView): model = MateriaLegislativa filterset_class = MateriaLegislativaFilterSet diff --git a/sapl/norma/views.py b/sapl/norma/views.py index 488e73c90..b82d83d39 100644 --- a/sapl/norma/views.py +++ b/sapl/norma/views.py @@ -30,8 +30,8 @@ from sapl.compilacao.views import IntegracaoTaView from sapl.crud.base import (RP_DETAIL, RP_LIST, Crud, CrudAux, MasterDetailCrud, make_pagination) from sapl.materia.models import Orgao -from sapl.utils import show_results_filter_set, get_client_ip,\ - sapn_is_enabled, MultiFormatOutputMixin +from sapl.utils import show_results_filter_set, get_client_ip, \ + sapn_is_enabled, MultiFormatOutputMixin, ratelimit_ip from .forms import (AnexoNormaJuridicaForm, NormaFilterSet, NormaJuridicaForm, NormaPesquisaSimplesForm, NormaRelacionadaForm, @@ -150,7 +150,10 @@ class NormaRelacionadaCrud(MasterDetailCrud): layout_key = 'NormaRelacionadaDetail' -@method_decorator(ratelimit(key='ip', rate='10/m', block=True), name='dispatch') +@method_decorator(ratelimit(key=ratelimit_ip, + rate='10/m', + block=True), + name='dispatch') class NormaPesquisaView(MultiFormatOutputMixin, FilterView): model = NormaJuridica filterset_class = NormaFilterSet @@ -236,7 +239,10 @@ class AnexoNormaJuridicaCrud(MasterDetailCrud): initial['ano'] = self.object.ano return initial - @method_decorator(ratelimit(key='ip', rate='10/m', block=True), name='dispatch') + @method_decorator(ratelimit(key=ratelimit_ip, + rate='10/m', + block=True), + name='dispatch') class DetailView(MasterDetailCrud.DetailView): form_class = AnexoNormaJuridicaForm layout_key = 'AnexoNormaJuridica' @@ -285,7 +291,10 @@ 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') + @method_decorator(ratelimit(key=ratelimit_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 @@ -343,7 +352,10 @@ class NormaCrud(Crud): layout_key = 'NormaJuridicaCreate' - @method_decorator(ratelimit(key='ip', rate='10/m', block=True), name='dispatch') + @method_decorator(ratelimit(key=ratelimit_ip, + rate='10/m', + block=True), + name='dispatch') class ListView(Crud.ListView): def get(self, request, *args, **kwargs): diff --git a/sapl/sessao/views.py b/sapl/sessao/views.py index 7df367379..63f6a39e7 100755 --- a/sapl/sessao/views.py +++ b/sapl/sessao/views.py @@ -48,8 +48,8 @@ from sapl.sessao.forms import ExpedienteMateriaForm, OrdemDiaForm, OrdemExpedien CorrespondenciaForm, CorrespondenciaEmLoteFilterSet from sapl.sessao.models import Correspondencia from sapl.settings import TIME_ZONE -from sapl.utils import show_results_filter_set, remover_acentos, get_client_ip,\ - MultiFormatOutputMixin, PautaMultiFormatOutputMixin +from sapl.utils import show_results_filter_set, remover_acentos, get_client_ip, \ + MultiFormatOutputMixin, PautaMultiFormatOutputMixin, ratelimit_ip from .forms import (AdicionarVariasMateriasFilterSet, BancadaForm, ExpedienteForm, JustificativaAusenciaForm, OcorrenciaSessaoForm, ListMateriaForm, @@ -3797,7 +3797,10 @@ class SessaoListView(ListView): return context -@method_decorator(ratelimit(key='ip', rate='10/m', block=True), name='dispatch') +@method_decorator(ratelimit(key=ratelimit_ip, + rate='10/m', + block=True), + name='dispatch') class PautaSessaoView(TemplateView): model = SessaoPlenaria template_name = "sessao/pauta_inexistente.html" @@ -3813,7 +3816,10 @@ class PautaSessaoView(TemplateView): reverse('sapl.sessao:pauta_sessao_detail', kwargs={'pk': sessao.pk})) -@method_decorator(ratelimit(key='ip', rate='10/m', block=True), name='dispatch') +@method_decorator(ratelimit(key=ratelimit_ip, + rate='10/m', + block=True), + name='dispatch') class PautaSessaoDetailView(PautaMultiFormatOutputMixin, DetailView): template_name = "sessao/pauta_sessao_detail.html" model = SessaoPlenaria diff --git a/sapl/utils.py b/sapl/utils.py index 6554c5aea..ee97094aa 100644 --- a/sapl/utils.py +++ b/sapl/utils.py @@ -402,12 +402,20 @@ def xstr(s): def get_client_ip(request): + from ratelimit.core import ip_mask x_forwarded_for = request.META.get('HTTP_X_FORWARDED_FOR') if x_forwarded_for: ip = x_forwarded_for.split(',')[0] else: - ip = request.META.get('REMOTE_ADDR') - return ip + ip = request.META.get('HTTP_X_REAL_IP') or request.META.get('REMOTE_ADDR') or '0.0.0.0' + return ip_mask(ip) + + +def ratelimit_ip(group, request): + """ + Ignore group param in django-ratelimit==3.0.1 + """ + return get_client_ip(request) def get_base_url(request):