Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Reverts account and frozen author fields to charfields. #4406

Merged
merged 8 commits into from
Sep 18, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
import core.model_utils
from django.db import migrations, models

import utils


class Migration(migrations.Migration):

Expand All @@ -19,32 +21,32 @@ class Migration(migrations.Migration):
migrations.AlterField(
model_name='account',
name='department',
field=core.model_utils.JanewayBleachCharField(blank=True, max_length=300, verbose_name='Department'),
field=models.CharField(blank=True, max_length=300, verbose_name='Department', validators=[utils.forms.plain_text_validator]),
),
migrations.AlterField(
model_name='account',
name='first_name',
field=core.model_utils.JanewayBleachCharField(max_length=300, verbose_name='First name'),
field=models.CharField(max_length=300, verbose_name='First name', validators=[utils.forms.plain_text_validator]),
),
migrations.AlterField(
model_name='account',
name='institution',
field=core.model_utils.JanewayBleachCharField(blank=True, max_length=1000, verbose_name='Institution'),
field=models.CharField(blank=True, max_length=1000, verbose_name='Institution', validators=[utils.forms.plain_text_validator]),
),
migrations.AlterField(
model_name='account',
name='last_name',
field=core.model_utils.JanewayBleachCharField(max_length=300, verbose_name='Last name'),
field=models.CharField(max_length=300, verbose_name='Last name', validators=[utils.forms.plain_text_validator]),
),
migrations.AlterField(
model_name='account',
name='middle_name',
field=core.model_utils.JanewayBleachCharField(blank=True, max_length=300, verbose_name='Middle name'),
field=models.CharField(blank=True, max_length=300, verbose_name='Middle name', validators=[utils.forms.plain_text_validator]),
),
migrations.AlterField(
model_name='account',
name='salutation',
field=core.model_utils.JanewayBleachCharField(blank=True, choices=[('Miss', 'Miss'), ('Ms', 'Ms'), ('Mrs', 'Mrs'), ('Mr', 'Mr'), ('Mx', 'Mx'), ('Dr', 'Dr'), ('Prof.', 'Prof.')], max_length=10, verbose_name='Salutation'),
field=models.CharField(blank=True, choices=[('Miss', 'Miss'), ('Ms', 'Ms'), ('Mrs', 'Mrs'), ('Mr', 'Mr'), ('Mx', 'Mx'), ('Dr', 'Dr'), ('Prof.', 'Prof.')], max_length=10, verbose_name='Salutation', validators=[utils.forms.plain_text_validator]),
),
migrations.AlterField(
model_name='account',
Expand All @@ -54,6 +56,6 @@ class Migration(migrations.Migration):
migrations.AlterField(
model_name='account',
name='suffix',
field=core.model_utils.JanewayBleachCharField(blank=True, max_length=300, verbose_name='Name suffix'),
field=models.CharField(blank=True, max_length=300, verbose_name='Name suffix', validators=[utils.forms.plain_text_validator]),
),
]
22 changes: 15 additions & 7 deletions src/core/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@
from submission import models as submission_models
from utils.logger import get_logger
from utils import logic as utils_logic
from utils.forms import plain_text_validator
from production import logic as production_logic

fs = JanewayFileSystemStorage()
Expand Down Expand Up @@ -235,48 +236,55 @@ class Account(AbstractBaseUser, PermissionsMixin):
username = models.CharField(max_length=254, unique=True, verbose_name=_('Username'))

name_prefix = models.CharField(max_length=10, blank=True)
first_name = JanewayBleachCharField(
first_name = models.CharField(
max_length=300,
blank=False,
verbose_name=_('First name'),
validators=[plain_text_validator],
)
middle_name = JanewayBleachCharField(
middle_name = models.CharField(
max_length=300,
blank=True,
verbose_name=_('Middle name'),
validators=[plain_text_validator],
)
last_name = JanewayBleachCharField(
last_name = models.CharField(
max_length=300,
blank=False,
verbose_name=_('Last name'),
validators=[plain_text_validator],
)

activation_code = models.CharField(max_length=100, null=True, blank=True)
salutation = JanewayBleachCharField(
salutation = models.CharField(
max_length=10,
choices=SALUTATION_CHOICES,
blank=True,
verbose_name=_('Salutation'),
validators=[plain_text_validator],
)
suffix = JanewayBleachCharField(
suffix = models.CharField(
max_length=300,
blank=True,
verbose_name=_('Name suffix'),
validators=[plain_text_validator],
)
biography = JanewayBleachField(
blank=True,
verbose_name=_('Biography'),
)
orcid = models.CharField(max_length=40, null=True, blank=True, verbose_name=_('ORCiD'))
institution = JanewayBleachCharField(
institution = models.CharField(
max_length=1000,
blank=True,
verbose_name=_('Institution'),
validators=[plain_text_validator],
)
department = JanewayBleachCharField(
department = models.CharField(
max_length=300,
blank=True,
verbose_name=_('Department'),
validators=[plain_text_validator],
)
twitter = models.CharField(max_length=300, null=True, blank=True, verbose_name=_('Twitter Handle'))
facebook = models.CharField(max_length=300, null=True, blank=True, verbose_name=_('Facebook Handle'))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import core.model_utils
from django.db import migrations, models
import utils.forms


class Migration(migrations.Migration):
Expand All @@ -15,12 +16,12 @@ class Migration(migrations.Migration):
migrations.AlterField(
model_name='frozenauthor',
name='department',
field=core.model_utils.JanewayBleachCharField(blank=True, max_length=300),
field=models.CharField(blank=True, max_length=300, validators=[utils.forms.plain_text_validator]),
),
migrations.AlterField(
model_name='frozenauthor',
name='first_name',
field=core.model_utils.JanewayBleachCharField(blank=True, max_length=300),
field=models.CharField(blank=True, max_length=300, validators=[utils.forms.plain_text_validator]),
),
migrations.AlterField(
model_name='frozenauthor',
Expand All @@ -40,26 +41,26 @@ class Migration(migrations.Migration):
migrations.AlterField(
model_name='frozenauthor',
name='institution',
field=core.model_utils.JanewayBleachCharField(blank=True, max_length=1000),
field=models.CharField(blank=True, max_length=1000, validators=[utils.forms.plain_text_validator]),
),
migrations.AlterField(
model_name='frozenauthor',
name='last_name',
field=core.model_utils.JanewayBleachCharField(blank=True, max_length=300),
field=models.CharField(blank=True, max_length=300, validators=[utils.forms.plain_text_validator]),
),
migrations.AlterField(
model_name='frozenauthor',
name='middle_name',
field=core.model_utils.JanewayBleachCharField(blank=True, max_length=300),
field=models.CharField(blank=True, max_length=300, validators=[utils.forms.plain_text_validator]),
),
migrations.AlterField(
model_name='frozenauthor',
name='name_prefix',
field=core.model_utils.JanewayBleachCharField(blank=True, help_text='Optional name prefix (e.g: Prof or Dr)', max_length=300),
field=models.CharField(blank=True, help_text='Optional name prefix (e.g: Prof or Dr)', max_length=300, validators=[utils.forms.plain_text_validator]),
),
migrations.AlterField(
model_name='frozenauthor',
name='name_suffix',
field=core.model_utils.JanewayBleachCharField(blank=True, help_text='Optional name suffix (e.g.: Jr or III)', max_length=300),
field=models.CharField(blank=True, help_text='Optional name suffix (e.g.: Jr or III)', max_length=300, validators=[utils.forms.plain_text_validator]),
),
]
44 changes: 33 additions & 11 deletions src/submission/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@
from review import models as review_models
from utils.function_cache import cache
from utils.logger import get_logger
from utils.forms import plain_text_validator
from journal import models as journal_models
from review.const import (
ReviewerDecisions as RD,
Expand Down Expand Up @@ -1911,23 +1912,44 @@ class FrozenAuthor(AbstractLastModifiedModel):
on_delete=models.SET_NULL,
)

name_prefix = JanewayBleachCharField(
name_prefix = models.CharField(
max_length=300,
blank=True,
help_text=_("Optional name prefix (e.g: Prof or Dr)")

)
name_suffix = JanewayBleachCharField(
help_text=_("Optional name prefix (e.g: Prof or Dr)"),
validators=[plain_text_validator],
)
name_suffix = models.CharField(
max_length=300,
blank=True,
help_text=_("Optional name suffix (e.g.: Jr or III)"),
validators=[plain_text_validator],
)
first_name = models.CharField(
max_length=300,
blank=True,
help_text=_("Optional name suffix (e.g.: Jr or III)")
validators=[plain_text_validator],
)
middle_name = models.CharField(
max_length=300,
blank=True,
validators=[plain_text_validator],
)
first_name = JanewayBleachCharField(max_length=300, blank=True)
middle_name = JanewayBleachCharField(max_length=300, blank=True)
last_name = JanewayBleachCharField(max_length=300, blank=True)
last_name = models.CharField(
max_length=300,
blank=True,
validators=[plain_text_validator],
)

institution = JanewayBleachCharField(max_length=1000, blank=True)
department = JanewayBleachCharField(max_length=300, blank=True)
institution = models.CharField(
max_length=1000,
blank=True,
validators=[plain_text_validator],
)
department = models.CharField(
max_length=300,
blank=True,
validators=[plain_text_validator],
)
frozen_biography = JanewayBleachField(
blank=True,
verbose_name=_('Frozen Biography'),
Expand Down
28 changes: 28 additions & 0 deletions src/submission/tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
from django.utils import translation, timezone
from django.urls.base import clear_script_prefix
from django.conf import settings
from django.core.exceptions import ValidationError
from django.shortcuts import reverse
from django.test.utils import override_settings

Expand Down Expand Up @@ -567,6 +568,33 @@ def test_author_form_with_good_orcid(self):
'0000-0003-2126-266X',
)

def test_author_form_harmful_inputs(self):
harmful_string = '<span onClick="alert()"> This are not the droids you are looking for </span>'
for i, attr in enumerate({
"first_name",
"last_name",
"middle_name",
"name_prefix",
"suffix",
"institution",
"department",
}):
form = forms.AuthorForm(
{
'first_name': 'Andy',
'last_name': 'Byers',
'biography': 'Andy',
'institution': 'Birkbeck, University of London',
'email': f'andy{i}@janeway.systems',
'orcid': 'https://orcid.org/0000-0003-2126-266X',
**{attr: harmful_string},
}
)
self.assertFalse(
form.is_valid(),
f"Harmful code injected into field '{attr}'"
)

@override_settings(URL_CONFIG='domain')
def test_article_encoding_bibtex(self):
article = helpers.create_article(
Expand Down
6 changes: 5 additions & 1 deletion src/templates/common/elements/orcid_registration.html
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,10 @@
[<a href="{% url 'core_register' %}">remove</a>]
</p>
{% else %}
<a href="{{ settings.ORCID_URL }}?client_id={{ settings.ORCID_CLIENT_ID }}&response_type=code&scope=/authenticate&redirect_uri={% orcid_redirect_uri 'register' %}" class="button expanded orcid-button">{% trans "Register with ORCiD" %}</a>
<a
href="{{ settings.ORCID_URL }}?client_id={{ settings.ORCID_CLIENT_ID }}&response_type=code&scope=/authenticate&redirect_uri={% orcid_redirect_uri 'register' %}"
class="{{ button_classes|default:"orcid-button" }}">
{% trans "Register with ORCiD" %}
</a>
{% endif %}
{% endif %}
2 changes: 1 addition & 1 deletion src/themes/OLH/templates/core/accounts/register.html
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ <h5>{% trans "Register for an account with" %} {{ request.press.name }}.</h5>
</ul>
<p>{% blocktrans %}For more information read our <a href="#" data-open="password-modal">password guide</a>.{% endblocktrans %}</p>

{% include "common/elements/orcid_registration.html" %}
{% include "common/elements/orcid_registration.html" with button_classes="button expanded orcid-button" %}

{% include "elements/forms/errors.html" with form=form %}

Expand Down
2 changes: 1 addition & 1 deletion src/themes/clean/templates/core/accounts/register.html
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ <h5>{% trans "Register for an account with" %} {{ request.press.name }}.</h5>
{% include "common/elements/password_rules.html" %}
</ul>
<p>{% blocktrans %}For more information read our <a href="#" data-toggle="modal" data-target="#passwordmodal">password guide</a>.{% endblocktrans %}</p>
{% include "common/elements/orcid_registration.html" %}
{% include "common/elements/orcid_registration.html" with button_classes="btn orcid-button btn-block" %}
<br>
{% bootstrap_form form %}
<p>
Expand Down
2 changes: 1 addition & 1 deletion src/themes/material/templates/core/accounts/register.html
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
<p>
{% blocktrans trimmed %}For more information read our <a href="#" data-target="passwordmodal" class="modal-trigger">password guide</a>.{% endblocktrans %}
</p>
{% include "common/elements/orcid_registration.html" %}
{% include "common/elements/orcid_registration.html" with button_classes="btn wide-button orcid-button" %}
<form method="POST">
{% include "elements/forms/errors.html" %}
{% csrf_token %}
Expand Down
40 changes: 40 additions & 0 deletions src/utils/forms.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import bleach
from django.forms import (
CharField,
CheckboxInput,
Expand All @@ -8,6 +9,7 @@
)
from django.utils.translation import gettext_lazy as _
from django.conf import settings
from django.core.exceptions import ValidationError

from modeltranslation import forms as mt_forms, translator
from captcha.fields import ReCaptchaField
Expand All @@ -18,6 +20,9 @@
from submission import models as submission_models


ENTITIES_MAP = (("&amp;", "&"), ("&gt;", ">"), ("&lt;", "<"))


class JanewayTranslationModelForm(mt_forms.TranslationModelForm):
def __init__(self, *args, **kwargs):
super(JanewayTranslationModelForm, self).__init__(*args, **kwargs)
Expand Down Expand Up @@ -109,3 +114,38 @@ def __init__(self, *args, **kwargs):
captcha = CharField(widget=HiddenInput, required=False)

self.fields["captcha"] = captcha


def text_sanitizer(text_value, tags=None, attrs=None, excl=ENTITIES_MAP):
""" A sanitizer for clearing potential harmful html/css/js from the input
:param text_value: the string to sanitize
:param tags: A list of allowed html tags
:param attrs: A dict of allowed html attributes
:param excl: A list of pairs of allowed items and their replacement
:return: Sanitized string
"""
tags = tags or []
attrs = attrs or {}
excl = excl or {}

cleaned = bleach.clean(
text_value,
tags=tags,
attributes=attrs,
strip=True,
)
# Allow certain entities that bleach won't whitelist
# https://github.com/mozilla/bleach/issues/192#issuecomment-2304545475
for escaped, raw in excl:
cleaned = cleaned.replace(escaped, raw)

return cleaned


def plain_text_validator(value):
""" A field validator that ensures a textual input has no harmful code"""
sanitized = text_sanitizer(value)
if value != sanitized:
raise ValidationError(
_("HTML is not allowed in this field")
)
Loading