mirror of https://github.com/interlegis/sapl.git
Browse Source
- nginx sapl.conf: return 444 for scanner extension probes (.php, .asp, .jsp, .env, etc.) before requests reach Gunicorn — zero Python cost - ratelimit.py: remove check 2b (scanner_probe) — dead code now that nginx handles it; remove unused `import os` - ratelimit.py: authenticated users skip the rl:ip:blocked check (check 2) to prevent anonymous NAT traffic from blocking legislative house staff - ratelimit.py: add _handle_not_found — post-response 404 counter per anonymous IP; blocks after RATE_LIMIT_404_THRESHOLD (default 10) hits in the anon window, catching path probes without known extensions - settings.py: replace RATE_LIMIT_SCANNER_EXTENSIONS with RATE_LIMIT_404_THRESHOLD; add RL_IP_404S Redis key constant - painel: remove dead mensagem/parlamentares/votacao templates, views, and URL entries — unreachable from any menu or template - RATE-LIMITER-PLAN.md: update decision flow, mermaid diagram, enforcement graduation table, and key schema to reflect all changes Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>rate-limiter-2026
9 changed files with 83 additions and 428 deletions
@ -1,120 +0,0 @@ |
|||||
{% load i18n %} |
|
||||
{% load common_tags %} |
|
||||
{% load render_bundle from webpack_loader %} |
|
||||
{% load webpack_static from webpack_loader %} |
|
||||
|
|
||||
<!DOCTYPE HTML> |
|
||||
<!--[if IE 8]> <html class="no-js lt-ie9" lang="pt-br"> <![endif]--> |
|
||||
<!--[if gt IE 8]><!--> |
|
||||
<html lang="pt-br"> |
|
||||
<!--<![endif]--> |
|
||||
|
|
||||
<head> |
|
||||
<meta charset="UTF-8"> |
|
||||
<!-- TODO: does it need this head_title here? --> |
|
||||
<title>{% block head_title %}{% trans 'SAPL - Sistema de Apoio ao Processo Legislativo' %}{% endblock %}</title> |
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0"> |
|
||||
|
|
||||
{% render_chunk_vendors 'css' %} |
|
||||
{% render_bundle 'global' 'css' %} |
|
||||
{% render_bundle 'painel' 'css' %} |
|
||||
|
|
||||
|
|
||||
<STYLE type="text/css"> |
|
||||
@media screen { |
|
||||
body {font-size: medium; color: white; line-height: 1em; background: black;} |
|
||||
} |
|
||||
</STYLE> |
|
||||
|
|
||||
</head> |
|
||||
<body> |
|
||||
<h1>{{ context.title }}</h1> |
|
||||
<input id="json_url" type="hidden" value="{% url 'sapl.painel:dados_painel' %}"> |
|
||||
<h2>Ajax refresh counter: <span id="counter"></span></h2> |
|
||||
<h3> |
|
||||
<span id="sessao_plenaria"></span><br/><br/> |
|
||||
<span id="sessao_plenaria_data"></span><br/><br/> |
|
||||
<span id="sessao_plenaria_hora_inicio"></span></br><br/> |
|
||||
<h2><span id="relogio"></span></h2></br><br/><br/> |
|
||||
<span id="materia_legislativa_texto"></span><br/> |
|
||||
<span id="observacao_materia"></span> |
|
||||
</h3> |
|
||||
</body> |
|
||||
|
|
||||
{% render_chunk_vendors 'js' %} |
|
||||
{% render_bundle 'global' 'js' %} |
|
||||
{% render_bundle 'painel' 'js' %} |
|
||||
|
|
||||
<script type="text/javascript"> |
|
||||
$(document).ready(function() { |
|
||||
|
|
||||
//TODO: replace by a fancy jQuery clock |
|
||||
function checkTime(i) { |
|
||||
if (i<10) {i = "0" + i}; // add zero in front of numbers < 10 |
|
||||
return i; |
|
||||
} |
|
||||
function startTime() { |
|
||||
var today=new Date(); |
|
||||
var h=today.getHours(); |
|
||||
var m=today.getMinutes(); |
|
||||
var s=today.getSeconds(); |
|
||||
m = checkTime(m); |
|
||||
s = checkTime(s); |
|
||||
$("#relogio").text(h+":"+m+":"+s) |
|
||||
var t = setTimeout(function(){ |
|
||||
startTime() |
|
||||
},500); |
|
||||
} |
|
||||
|
|
||||
startTime(); |
|
||||
|
|
||||
var counter = 1; |
|
||||
(function poll() { |
|
||||
$.ajax({ |
|
||||
url: $("#json_url").val(), |
|
||||
type: "GET", |
|
||||
success: function(data) { |
|
||||
|
|
||||
//TODO: json spitted out is very complex, have to simplify/flat it |
|
||||
//TODO: probably building it by hand on REST side |
|
||||
|
|
||||
console.debug(data) |
|
||||
|
|
||||
var presentes = $("#parlamentares"); |
|
||||
presentes.children().remove(); |
|
||||
|
|
||||
presentes_ordem_dia = data.presentes_ordem_dia |
|
||||
$.each(presentes_ordem_dia, function(index, parlamentar) { |
|
||||
$('<li />', {text: parlamentar.nome + '/' + parlamentar.partido + ' ' + parlamentar.voto }).appendTo(presentes); |
|
||||
}); |
|
||||
|
|
||||
var votacao = $("#votacao") |
|
||||
votacao.children().remove() |
|
||||
votacao.append("<li>Sim: " + data["numero_votos_sim"] + "</li>") |
|
||||
votacao.append("<li>Não: " + data["numero_votos_nao"] + "</li>") |
|
||||
votacao.append("<li>Abstenções: " + data["numero_abstencoes"] + "</li>") |
|
||||
votacao.append("<li>Presentes: " + data["presentes"] + "</li>") |
|
||||
votacao.append("<li>Total votos: " + data["total_votos"] + "</li>") |
|
||||
|
|
||||
$("#sessao_plenaria").text(data["sessao_plenaria"]) |
|
||||
$("#sessao_plenaria_data").text("Data Início: " + data["sessao_plenaria_data"]) |
|
||||
$("#sessao_plenaria_hora_inicio").text("Hora Início: " + data["sessao_plenaria_hora_inicio"]) |
|
||||
|
|
||||
$("#materia_legislativa_texto").text(data["materia_legislativa_texto"]) |
|
||||
$("#observacao_materia").text(data["observacao_materia"]) |
|
||||
$("#resultado_votacao").text(data["tipo_resultado"]) |
|
||||
|
|
||||
$("#counter").text(counter); |
|
||||
counter++; |
|
||||
}, |
|
||||
error: function(err) { |
|
||||
console.error(err); |
|
||||
}, |
|
||||
dataType: "json", |
|
||||
//complete: setTimeout(function() {poll()}, 5000), |
|
||||
timeout: 20000 // TODO: decrease |
|
||||
}) |
|
||||
})(); |
|
||||
}); |
|
||||
</script> |
|
||||
</html> |
|
||||
@ -1,128 +0,0 @@ |
|||||
{% load i18n %} |
|
||||
{% load common_tags %} |
|
||||
|
|
||||
{% load render_bundle from webpack_loader %} |
|
||||
{% load webpack_static from webpack_loader %} |
|
||||
|
|
||||
<!DOCTYPE HTML> |
|
||||
<!--[if IE 8]> <html class="no-js lt-ie9" lang="pt-br"> <![endif]--> |
|
||||
<!--[if gt IE 8]><!--> |
|
||||
<html lang="pt-br"> |
|
||||
<!--<![endif]--> |
|
||||
|
|
||||
<head> |
|
||||
<meta charset="UTF-8"> |
|
||||
<!-- TODO: does it need this head_title here? --> |
|
||||
<title>{% block head_title %}{% trans 'SAPL - Sistema de Apoio ao Processo Legislativo' %}{% endblock %}</title> |
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0"> |
|
||||
|
|
||||
{% render_chunk_vendors 'css' %} |
|
||||
{% render_bundle 'global' 'css' %} |
|
||||
{% render_bundle 'painel' 'css' %} |
|
||||
|
|
||||
|
|
||||
|
|
||||
<STYLE type="text/css"> |
|
||||
@media screen { |
|
||||
body {font-size: medium; color: white; line-height: 1em; background: black;} |
|
||||
} |
|
||||
</STYLE> |
|
||||
|
|
||||
</head> |
|
||||
<body> |
|
||||
<h1>{{ context.title }}</h1> |
|
||||
<input id="json_url" type="hidden" value="{% url 'sapl.painel:dados_painel' %}"> |
|
||||
<h3> |
|
||||
<span id="sessao_plenaria"></span><br/><br/> |
|
||||
<span id="sessao_plenaria_data"></span><br/><br/> |
|
||||
<span id="sessao_plenaria_hora_inicio"></span></br><br/> |
|
||||
<h2><span id="relogio"></span></h2> |
|
||||
<table> |
|
||||
<tr> |
|
||||
<td> |
|
||||
<ul id="parlamentares"> |
|
||||
</ul> |
|
||||
</td> |
|
||||
</tr> |
|
||||
</table> |
|
||||
</h3> |
|
||||
</body> |
|
||||
|
|
||||
{% render_chunk_vendors 'js' %} |
|
||||
{% render_bundle 'global' 'js' %} |
|
||||
{% render_bundle 'painel' 'js' %} |
|
||||
|
|
||||
<script type="text/javascript"> |
|
||||
$(document).ready(function() { |
|
||||
|
|
||||
//TODO: replace by a fancy jQuery clock |
|
||||
function checkTime(i) { |
|
||||
if (i<10) {i = "0" + i}; // add zero in front of numbers < 10 |
|
||||
return i; |
|
||||
} |
|
||||
function startTime() { |
|
||||
var today=new Date(); |
|
||||
var h=today.getHours(); |
|
||||
var m=today.getMinutes(); |
|
||||
var s=today.getSeconds(); |
|
||||
m = checkTime(m); |
|
||||
s = checkTime(s); |
|
||||
$("#relogio").text(h+":"+m+":"+s) |
|
||||
var t = setTimeout(function(){ |
|
||||
startTime() |
|
||||
},500); |
|
||||
} |
|
||||
|
|
||||
startTime(); |
|
||||
|
|
||||
var counter = 1; |
|
||||
(function poll() { |
|
||||
$.ajax({ |
|
||||
url: $("#json_url").val(), |
|
||||
type: "GET", |
|
||||
success: function(data) { |
|
||||
|
|
||||
//TODO: json spitted out is very complex, have to simplify/flat it |
|
||||
//TODO: probably building it by hand on REST side |
|
||||
|
|
||||
console.debug(data) |
|
||||
|
|
||||
var presentes = $("#parlamentares"); |
|
||||
presentes.children().remove(); |
|
||||
|
|
||||
presentes_ordem_dia = data.presentes_ordem_dia |
|
||||
$.each(presentes_ordem_dia, function(index, parlamentar) { |
|
||||
$('<li />', {text: parlamentar.nome + '/' + parlamentar.partido }).appendTo(presentes); |
|
||||
/*$('<li />', {text: parlamentar.nome + '/' + parlamentar.partido + ' ' + parlamentar.voto }).appendTo(presentes);*/ |
|
||||
}); |
|
||||
|
|
||||
var votacao = $("#votacao") |
|
||||
votacao.children().remove() |
|
||||
votacao.append("<li>Sim: " + data["numero_votos_sim"] + "</li>") |
|
||||
votacao.append("<li>Não: " + data["numero_votos_nao"] + "</li>") |
|
||||
votacao.append("<li>Abstenções: " + data["numero_abstencoes"] + "</li>") |
|
||||
votacao.append("<li>Presentes: " + data["presentes"] + "</li>") |
|
||||
votacao.append("<li>Total votos: " + data["total_votos"] + "</li>") |
|
||||
|
|
||||
$("#sessao_plenaria").text(data["sessao_plenaria"]) |
|
||||
$("#sessao_plenaria_data").text("Data Início: " + data["sessao_plenaria_data"]) |
|
||||
$("#sessao_plenaria_hora_inicio").text("Hora Início: " + data["sessao_plenaria_hora_inicio"]) |
|
||||
|
|
||||
$("#materia_legislativa_texto").text(data["materia_legislativa_texto"]) |
|
||||
$("#observacao_materia").text(data["observacao_materia"]) |
|
||||
$("#resultado_votacao").text(data["tipo_resultado"]) |
|
||||
|
|
||||
$("#counter").text(counter); |
|
||||
counter++; |
|
||||
}, |
|
||||
error: function(err) { |
|
||||
console.error(err); |
|
||||
}, |
|
||||
dataType: "json", |
|
||||
//complete: setTimeout(function() {poll()}, 5000), |
|
||||
timeout: 20000 // TODO: decrease |
|
||||
}) |
|
||||
})(); |
|
||||
}); |
|
||||
</script> |
|
||||
</html> |
|
||||
@ -1,123 +0,0 @@ |
|||||
{% load i18n %} |
|
||||
{% load render_bundle from webpack_loader %} |
|
||||
{% load webpack_static from webpack_loader %} |
|
||||
|
|
||||
<!DOCTYPE HTML> |
|
||||
<!--[if IE 8]> <html class="no-js lt-ie9" lang="pt-br"> <![endif]--> |
|
||||
<!--[if gt IE 8]><!--> |
|
||||
<html lang="pt-br"> |
|
||||
<!--<![endif]--> |
|
||||
|
|
||||
<head> |
|
||||
<meta charset="UTF-8"> |
|
||||
<!-- TODO: does it need this head_title here? --> |
|
||||
<title>{% block head_title %}{% trans 'SAPL - Sistema de Apoio ao Processo Legislativo' %}{% endblock %}</title> |
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0"> |
|
||||
|
|
||||
{% render_chunk_vendors 'css' %} |
|
||||
{% render_bundle 'global' 'css' %} |
|
||||
{% render_bundle 'painel' 'css' %} |
|
||||
|
|
||||
<STYLE type="text/css"> |
|
||||
@media screen { |
|
||||
body {font-size: medium; color: white; line-height: 1em; background: black;} |
|
||||
} |
|
||||
</STYLE> |
|
||||
</head> |
|
||||
<body> |
|
||||
<h1>{{ context.title }}</h1> |
|
||||
<input id="json_url" type="hidden" value="{% url 'sapl.painel:dados_painel' %}"> |
|
||||
<h3> |
|
||||
<span id="sessao_plenaria"></span><br/><br/> |
|
||||
<span id="sessao_plenaria_data"></span><br/><br/> |
|
||||
<span id="sessao_plenaria_hora_inicio"></span></br><br/> |
|
||||
<h2><span id="relogio"></span></h2> |
|
||||
<table> |
|
||||
<tr> |
|
||||
<td> |
|
||||
<ul id="votacao"> |
|
||||
</ul> |
|
||||
</td> |
|
||||
</tr> |
|
||||
</table> |
|
||||
<span id="resultado_votacao"></span><br/> |
|
||||
</h3> |
|
||||
</body> |
|
||||
|
|
||||
{% render_chunk_vendors 'js' %} |
|
||||
{% render_bundle 'global' 'js' %} |
|
||||
{% render_bundle 'painel' 'js' %} |
|
||||
|
|
||||
<script type="text/javascript"> |
|
||||
$(document).ready(function() { |
|
||||
|
|
||||
//TODO: replace by a fancy jQuery clock |
|
||||
function checkTime(i) { |
|
||||
if (i<10) {i = "0" + i}; // add zero in front of numbers < 10 |
|
||||
return i; |
|
||||
} |
|
||||
function startTime() { |
|
||||
var today=new Date(); |
|
||||
var h=today.getHours(); |
|
||||
var m=today.getMinutes(); |
|
||||
var s=today.getSeconds(); |
|
||||
m = checkTime(m); |
|
||||
s = checkTime(s); |
|
||||
$("#relogio").text(h+":"+m+":"+s) |
|
||||
var t = setTimeout(function(){ |
|
||||
startTime() |
|
||||
},500); |
|
||||
} |
|
||||
|
|
||||
startTime(); |
|
||||
|
|
||||
var counter = 1; |
|
||||
(function poll() { |
|
||||
$.ajax({ |
|
||||
url: $("#json_url").val(), |
|
||||
type: "GET", |
|
||||
success: function(data) { |
|
||||
|
|
||||
//TODO: json spitted out is very complex, have to simplify/flat it |
|
||||
//TODO: probably building it by hand on REST side |
|
||||
|
|
||||
console.debug(data) |
|
||||
|
|
||||
var presentes = $("#parlamentares"); |
|
||||
presentes.children().remove(); |
|
||||
|
|
||||
presentes_ordem_dia = data.presentes_ordem_dia |
|
||||
$.each(presentes_ordem_dia, function(index, parlamentar) { |
|
||||
$('<li />', {text: parlamentar.nome + '/' + parlamentar.partido + ' ' + parlamentar.voto }).appendTo(presentes); |
|
||||
}); |
|
||||
|
|
||||
var votacao = $("#votacao") |
|
||||
votacao.children().remove() |
|
||||
votacao.append("<li>Sim: " + data["numero_votos_sim"] + "</li>") |
|
||||
votacao.append("<li>Não: " + data["numero_votos_nao"] + "</li>") |
|
||||
votacao.append("<li>Abstenções: " + data["numero_abstencoes"] + "</li>") |
|
||||
votacao.append("<li>Presentes: " + data["presentes"] + "</li>") |
|
||||
votacao.append("<li>Total votos: " + data["total_votos"] + "</li>") |
|
||||
|
|
||||
$("#sessao_plenaria").text(data["sessao_plenaria"]) |
|
||||
$("#sessao_plenaria_data").text("Data Início: " + data["sessao_plenaria_data"]) |
|
||||
$("#sessao_plenaria_hora_inicio").text("Hora Início: " + data["sessao_plenaria_hora_inicio"]) |
|
||||
|
|
||||
$("#materia_legislativa_texto").text(data["materia_legislativa_texto"]) |
|
||||
$("#observacao_materia").text(data["observacao_materia"]) |
|
||||
$("#resultado_votacao").text(data["tipo_resultado"]) |
|
||||
|
|
||||
$("#counter").text(counter); |
|
||||
counter++; |
|
||||
}, |
|
||||
error: function(err) { |
|
||||
console.error(err); |
|
||||
}, |
|
||||
dataType: "json", |
|
||||
//complete: setTimeout(function() {poll()}, 5000), |
|
||||
timeout: 20000 // TODO: decrease |
|
||||
}) |
|
||||
})(); |
|
||||
}); |
|
||||
</script> |
|
||||
</html> |
|
||||
Loading…
Reference in new issue