mirror of https://github.com/interlegis/sapl.git
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
163 lines
5.5 KiB
163 lines
5.5 KiB
import pytest
|
|
from model_bakery import baker
|
|
|
|
from sapl.crispy_layout_mixin import get_field_display
|
|
from sapl.lexml.models import LexmlProvedor
|
|
from sapl.protocoloadm.models import TramitacaoAdministrativo
|
|
from sapl.sanitize import sanitize_field, sanitize_html, sanitize_scope
|
|
from sapl.sessao.models import ExpedienteSessao
|
|
|
|
|
|
def test_plain_remove_marcacao_e_preserva_texto():
|
|
assert sanitize_html('<script>alert(1)</script>Ciente') == 'Ciente'
|
|
assert sanitize_html('Encaminhado <b>ao</b> setor') == \
|
|
'Encaminhado ao setor'
|
|
assert sanitize_html('<img src=x onerror=alert(1)>') == ''
|
|
assert sanitize_html('<div>a</div><div>b</div>') == 'ab'
|
|
|
|
|
|
def test_plain_escapa_caracteres_especiais():
|
|
assert sanitize_html('Valor < 10 & prazo > 5') == \
|
|
'Valor < 10 & prazo > 5'
|
|
|
|
|
|
def test_plain_preserva_quebras_de_linha():
|
|
# get_field_display converte \n em <br/> depois de sanitizar
|
|
assert sanitize_html('linha1\nlinha2') == 'linha1\nlinha2'
|
|
|
|
|
|
def test_valores_vazios_atravessam():
|
|
assert sanitize_html('') == ''
|
|
assert sanitize_html(None) is None
|
|
assert sanitize_html('', rich=True) == ''
|
|
|
|
|
|
@pytest.mark.parametrize('valor', [
|
|
'<script>alert(1)</script>Ciente',
|
|
'Valor < 10 & prazo > 5',
|
|
'Encaminhado <b>ao</b> <a href="https://x">setor</a>',
|
|
'texto & cia',
|
|
])
|
|
def test_plain_e_idempotente(valor):
|
|
"""Propriedade da qual dependem as duas camadas (pre_save + renderização).
|
|
|
|
Se sanitizar duas vezes não fosse estável, o valor gravado seria
|
|
re-escapado a cada exibição.
|
|
"""
|
|
uma_vez = sanitize_html(valor)
|
|
assert sanitize_html(uma_vez) == uma_vez
|
|
|
|
|
|
@pytest.mark.parametrize('valor', [
|
|
'<a href="https://camara.gov.br" target="_blank">Portal</a>',
|
|
'<p style="text-align: center;">centro</p>',
|
|
'<table><tr><td colspan="2">c</td></tr></table>',
|
|
'<script>alert(1)</script><b>ok</b>',
|
|
])
|
|
def test_rich_e_idempotente(valor):
|
|
uma_vez = sanitize_html(valor, rich=True)
|
|
assert sanitize_html(uma_vez, rich=True) == uma_vez
|
|
|
|
|
|
def test_rich_preserva_links():
|
|
saida = sanitize_html(
|
|
'<a href="https://camara.gov.br" target="_blank">Portal</a>',
|
|
rich=True)
|
|
assert 'href="https://camara.gov.br"' in saida
|
|
assert 'target="_blank"' in saida
|
|
assert 'rel="noopener noreferrer"' in saida
|
|
assert '>Portal</a>' in saida
|
|
|
|
assert 'href="/materia/123"' in sanitize_html(
|
|
'<a href="/materia/123">Matéria</a>', rich=True)
|
|
assert 'href="mailto:a@b.c"' in sanitize_html(
|
|
'<a href="mailto:a@b.c">mail</a>', rich=True)
|
|
|
|
|
|
def test_rich_remove_href_perigosa_mas_mantem_o_texto():
|
|
saida = sanitize_html(
|
|
'<a href="javascript:alert(1)">clique</a>', rich=True)
|
|
assert 'javascript' not in saida
|
|
assert 'clique' in saida
|
|
|
|
|
|
def test_rich_remove_script_e_manipuladores_de_evento():
|
|
saida = sanitize_html('<script>alert(1)</script><b>ok</b>', rich=True)
|
|
assert saida == '<b>ok</b>'
|
|
|
|
assert 'onclick' not in sanitize_html(
|
|
'<a href="#" onclick="steal()">x</a>', rich=True)
|
|
assert 'onerror' not in sanitize_html(
|
|
'<img src="x" onerror="alert(1)">', rich=True)
|
|
|
|
|
|
def test_rich_preserva_formatacao_do_tinymce():
|
|
"""Protege contra regressão visual no conteúdo já cadastrado."""
|
|
assert 'style="text-align: center;"' in sanitize_html(
|
|
'<p style="text-align: center;">centro</p>', rich=True)
|
|
|
|
saida = sanitize_html(
|
|
'<table><tr><td colspan="2">c</td></tr></table>', rich=True)
|
|
assert '<table>' in saida and 'colspan="2"' in saida
|
|
|
|
assert sanitize_html('<ul><li>a</li><li>b</li></ul>', rich=True) == \
|
|
'<ul><li>a</li><li>b</li></ul>'
|
|
|
|
|
|
def test_sanitize_scope():
|
|
assert sanitize_scope(TramitacaoAdministrativo, 'texto') == 'plain'
|
|
assert sanitize_scope(ExpedienteSessao, 'conteudo') == 'rich'
|
|
assert sanitize_scope(LexmlProvedor, 'xml') == 'exempt'
|
|
|
|
|
|
def test_sanitize_field_respeita_isencao():
|
|
xml = '<xml><a href="javascript:x">y</a></xml>'
|
|
assert sanitize_field(LexmlProvedor, 'xml', xml) == xml
|
|
|
|
|
|
@pytest.mark.django_db
|
|
def test_pre_save_sanitiza_campo_simples():
|
|
t = baker.make(TramitacaoAdministrativo,
|
|
texto='<script>alert(1)</script>Ciente <b>ok</b>')
|
|
t.refresh_from_db()
|
|
assert t.texto == 'Ciente ok'
|
|
|
|
|
|
@pytest.mark.django_db
|
|
def test_pre_save_sanitiza_campo_rico_preservando_html():
|
|
e = baker.make(ExpedienteSessao,
|
|
conteudo='<b>x</b><script>alert(1)</script>'
|
|
'<a href="https://a.b" target="_blank">l</a>')
|
|
e.refresh_from_db()
|
|
assert '<script>' not in e.conteudo
|
|
assert '<b>x</b>' in e.conteudo
|
|
assert 'href="https://a.b"' in e.conteudo
|
|
|
|
|
|
@pytest.mark.django_db
|
|
def test_pre_save_nao_toca_modelo_isento():
|
|
xml = '<xml>a & b <script>x</script></xml>'
|
|
p = baker.make(LexmlProvedor, xml=xml)
|
|
p.refresh_from_db()
|
|
assert p.xml == xml
|
|
|
|
|
|
@pytest.mark.django_db
|
|
def test_get_field_display_nao_devolve_script():
|
|
t = TramitacaoAdministrativo(texto='<script>alert(1)</script>Ciente')
|
|
__, display = get_field_display(t, 'texto')
|
|
assert '<script>' not in display
|
|
assert 'Ciente' in display
|
|
|
|
|
|
@pytest.mark.django_db
|
|
def test_get_field_display_protege_linha_legada():
|
|
"""Linhas gravadas antes do pre_save não passam pela camada de entrada."""
|
|
t = baker.make(TramitacaoAdministrativo, texto='ok')
|
|
TramitacaoAdministrativo.objects.filter(pk=t.pk).update(
|
|
texto='<script>alert(1)</script>legado')
|
|
t.refresh_from_db()
|
|
assert t.texto == '<script>alert(1)</script>legado'
|
|
|
|
__, display = get_field_display(t, 'texto')
|
|
assert '<script>' not in display
|
|
|