enh Sanear con `bleach` la información introducida por los usuarios

Se purifica el HTML antes de guardar, usando la función `clean()` del formulario.

Por si acaso hubiera información anterior no saneada, se purifica también
al mostrarla, usando el filtro personalizado `limpiar`.
parent e03e82fa
Pipeline #524 failed with stage
in 0 seconds
......@@ -20,6 +20,7 @@ django-summernote = "*"
django-tables2 = "==2.2.1"
django-templated-email = "*"
pypandoc = "*"
bleach = "*"
[requires]
python_version = "3.7"
{
"_meta": {
"hash": {
"sha256": "4f6a29f13849afa5851cd65ae6bce2dbc9c53829ac6e87202dc1bd2f85604d61"
"sha256": "b9eaa4e1b4707f99413218dc1aa9c4039187b19ce6588e1aed7ac7826347b999"
},
"pipfile-spec": 6,
"requires": {
......@@ -23,6 +23,14 @@
],
"version": "==3.2.3"
},
"bleach": {
"hashes": [
"sha256:213336e49e102af26d9cde77dd2d0397afabc5a6bf2fed985dc35b5d1e285a16",
"sha256:3fdf7f77adcf649c9911387df51254b813185e32b2c6619f690b593a617e19fa"
],
"index": "pypi",
"version": "==3.1.0"
},
"certifi": {
"hashes": [
"sha256:017c25db2a153ce562900032d5bc68e9f191e44e9a0f762f373977de9df1fbb3",
......@@ -284,12 +292,19 @@
],
"version": "==1.25.8"
},
"webencodings": {
"hashes": [
"sha256:a0af1213f3c2226497a97e2b3aa01a7e4bee4f403f95be16fc9acd2947514a78",
"sha256:b36a1c245f2d304965eb4e0a82848379241dc04b865afcc4aab16748587e1923"
],
"version": "==0.5.1"
},
"wheel": {
"hashes": [
"sha256:48e082fac9a549bb30abcb71360db41e9e999f63bfc9933fdb7339ba7205330f",
"sha256:664b9c5033ee7cd5aa6b355bc8a4a5915eadb7612e7b0acab1aa71f005457107"
"sha256:8788e9155fe14f54164c1b9eb0a319d98ef02c160725587ad60f14ddc57b6f96",
"sha256:df277cb51e61359aba502208d680f90c0493adec6f0e848af94948778aed386e"
],
"version": "==0.34.1"
"version": "==0.34.2"
},
"xmlsec": {
"hashes": [
......
# See <https://docs.djangoproject.com/en/3.0/howto/custom-template-tags/>
import bleach
import urllib.parse
from django import template
from django.urls import reverse
from django.utils.safestring import mark_safe
from annoying.functions import get_config
register = template.Library()
......@@ -60,3 +64,19 @@ def get_attr_verbose_name(obj, attr):
def has_group(user, group_name):
"""Comprueba si el usuario pertenece al grupo indicado."""
return user.groups.filter(name=group_name).exists()
# See <https://bleach.readthedocs.io/en/latest/clean.html>
cleaner = bleach.Cleaner(
tags=(bleach.sanitizer.ALLOWED_TAGS + get_config("ADDITIONAL_ALLOWED_TAGS")),
attributes=get_config("ALLOWED_ATTRIBUTES"),
styles=get_config("ALLOWED_STYLES"),
protocols=get_config("ALLOWED_PROTOCOLS"),
strip=True,
strip_comments=True,
)
@register.filter
def limpiar(text):
return mark_safe(cleaner.clean(text))
import json
from datetime import date
import bleach
import pypandoc
from django.conf import settings
from django.contrib import messages
from django.contrib.auth.mixins import (
......@@ -15,9 +17,12 @@ from django.forms.models import modelform_factory
from django.http import Http404
from django.shortcuts import get_object_or_404, redirect
from django.urls import reverse_lazy
from django.utils.safestring import mark_safe
from django.utils.translation import gettext_lazy as _
from django.views.generic import DetailView, RedirectView, TemplateView
from django.views.generic.edit import CreateView, DeleteView, UpdateView
from annoying.functions import get_config
from django_summernote.widgets import SummernoteWidget
from django_tables2.views import SingleTableView
from templated_email import send_templated_mail
......@@ -648,6 +653,28 @@ class ProyectoUpdateFieldView(LoginRequiredMixin, ChecksMixin, UpdateView):
)
formulario.as_p = as_p
def clean(self):
cleaned_data = super(formulario, self).clean()
texto = cleaned_data.get(campo)
# See <https://bleach.readthedocs.io/en/latest/clean.html>
cleaned_data[campo] = mark_safe(
bleach.clean(
texto,
tags=(
bleach.sanitizer.ALLOWED_TAGS
+ get_config("ADDITIONAL_ALLOWED_TAGS")
),
attributes=get_config("ALLOWED_ATTRIBUTES"),
styles=get_config("ALLOWED_STYLES"),
protocols=get_config("ALLOWED_PROTOCOLS"),
strip=True,
)
)
return cleaned_data
formulario.clean = clean
return formulario
self.fields = (campo,)
return super().get_form_class()
......
-i https://pypi.org/simple
asgiref==3.2.3
bleach==3.1.0
certifi==2019.11.28
chardet==3.0.4
cx-oracle==7.3.0
......@@ -29,5 +30,6 @@ social-auth-app-django==3.1.0
social-auth-core[saml]==3.2.0
sqlparse==0.3.0
urllib3==1.25.8
wheel==0.34.1
webencodings==0.5.1
wheel==0.34.2
xmlsec==1.3.3
......@@ -164,9 +164,8 @@
{% endif %}
<br />
{# TODO: filtro para HTML procedente de procesador de textos #}
<h3>{% trans 'Descripción' %}</h3>
<p>{{ proyecto.descripcion | safe }}</p>
<p>{{ proyecto.descripcion | limpiar }}</p>
{% if permitir_edicion %}
<p>
......@@ -178,7 +177,7 @@
{% for campo in campos %}
<h3>{{ proyecto | get_attr_verbose_name:campo }}</h3>
<p>{{ proyecto | get_obj_attr:campo | default:"" | safe }}</p>
<p>{{ proyecto | get_obj_attr:campo | default:"" | limpiar }}</p>
{% if permitir_edicion %}
<p>
<a href="{% url 'proyecto_update_field' proyecto.id campo %}" class="btn btn-info btn-sm">
......@@ -200,7 +199,7 @@
{% endif %}
<h3>{{ proyecto | get_attr_verbose_name:"financiacion" }}</h3>
<p>{{ proyecto.financiacion | default:"" | safe }}</p>
<p>{{ proyecto.financiacion | default:"" | limpiar }}</p>
{% if permitir_edicion %}
<p>
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment