Skip to content

Commit

Permalink
feat: discourage URLs in Person names (#7453)
Browse files Browse the repository at this point in the history
* feat: disallow @ and : in name/ascii

@ has long been disallowed via validation in the
views and "/" has been disallowed for the name
field via a validator. This adds @ and : to the
validator and applies it to the name, plain,
ascii, and ascii_short fields. This should
apply everywhere we use a ModelForm.

* test: update test

* chore: migration
  • Loading branch information
jennifer-richards committed May 22, 2024
1 parent c290525 commit d5009ee
Show file tree
Hide file tree
Showing 3 changed files with 96 additions and 8 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
# Generated by Django 4.2.13 on 2024-05-22 18:50

from django.db import migrations, models
import ietf.person.models


class Migration(migrations.Migration):

dependencies = [
("person", "0001_initial"),
]

operations = [
migrations.AlterField(
model_name="historicalperson",
name="ascii",
field=models.CharField(
help_text="Name as rendered in ASCII (Latin, unaccented) characters.",
max_length=255,
validators=[ietf.person.models.name_character_validator],
verbose_name="Full Name (ASCII)",
),
),
migrations.AlterField(
model_name="historicalperson",
name="ascii_short",
field=models.CharField(
blank=True,
help_text="Example: A. Nonymous. Fill in this with initials and surname only if taking the initials and surname of the ASCII name above produces an incorrect initials-only form. (Blank is OK).",
max_length=32,
null=True,
validators=[ietf.person.models.name_character_validator],
verbose_name="Abbreviated Name (ASCII)",
),
),
migrations.AlterField(
model_name="historicalperson",
name="plain",
field=models.CharField(
blank=True,
default="",
help_text="Use this if you have a Spanish double surname. Don't use this for nicknames, and don't use it unless you've actually observed that the datatracker shows your name incorrectly.",
max_length=64,
validators=[ietf.person.models.name_character_validator],
verbose_name="Plain Name correction (Unicode)",
),
),
migrations.AlterField(
model_name="person",
name="ascii",
field=models.CharField(
help_text="Name as rendered in ASCII (Latin, unaccented) characters.",
max_length=255,
validators=[ietf.person.models.name_character_validator],
verbose_name="Full Name (ASCII)",
),
),
migrations.AlterField(
model_name="person",
name="ascii_short",
field=models.CharField(
blank=True,
help_text="Example: A. Nonymous. Fill in this with initials and surname only if taking the initials and surname of the ASCII name above produces an incorrect initials-only form. (Blank is OK).",
max_length=32,
null=True,
validators=[ietf.person.models.name_character_validator],
verbose_name="Abbreviated Name (ASCII)",
),
),
migrations.AlterField(
model_name="person",
name="plain",
field=models.CharField(
blank=True,
default="",
help_text="Use this if you have a Spanish double surname. Don't use this for nicknames, and don't use it unless you've actually observed that the datatracker shows your name incorrectly.",
max_length=64,
validators=[ietf.person.models.name_character_validator],
verbose_name="Plain Name correction (Unicode)",
),
),
]
14 changes: 9 additions & 5 deletions ietf/person/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,12 @@


def name_character_validator(value):
if '/' in value:
raise ValidationError('Name cannot contain "/" character.')
disallowed = "@:/"
found = set(disallowed).intersection(value)
if len(found) > 0:
raise ValidationError(
f"This name cannot contain the characters {', '.join(disallowed)}"
)


class Person(models.Model):
Expand All @@ -48,11 +52,11 @@ class Person(models.Model):
# The normal unicode form of the name. This must be
# set to the same value as the ascii-form if equal.
name = models.CharField("Full Name (Unicode)", max_length=255, db_index=True, help_text="Preferred long form of name.", validators=[name_character_validator])
plain = models.CharField("Plain Name correction (Unicode)", max_length=64, default='', blank=True, help_text="Use this if you have a Spanish double surname. Don't use this for nicknames, and don't use it unless you've actually observed that the datatracker shows your name incorrectly.")
plain = models.CharField("Plain Name correction (Unicode)", max_length=64, default='', blank=True, help_text="Use this if you have a Spanish double surname. Don't use this for nicknames, and don't use it unless you've actually observed that the datatracker shows your name incorrectly.", validators=[name_character_validator])
# The normal ascii-form of the name.
ascii = models.CharField("Full Name (ASCII)", max_length=255, help_text="Name as rendered in ASCII (Latin, unaccented) characters.")
ascii = models.CharField("Full Name (ASCII)", max_length=255, help_text="Name as rendered in ASCII (Latin, unaccented) characters.", validators=[name_character_validator])
# The short ascii-form of the name. Also in alias table if non-null
ascii_short = models.CharField("Abbreviated Name (ASCII)", max_length=32, null=True, blank=True, help_text="Example: A. Nonymous. Fill in this with initials and surname only if taking the initials and surname of the ASCII name above produces an incorrect initials-only form. (Blank is OK).")
ascii_short = models.CharField("Abbreviated Name (ASCII)", max_length=32, null=True, blank=True, help_text="Example: A. Nonymous. Fill in this with initials and surname only if taking the initials and surname of the ASCII name above produces an incorrect initials-only form. (Blank is OK).", validators=[name_character_validator])
pronouns_selectable = jsonfield.JSONCharField("Pronouns", max_length=120, blank=True, null=True, default=list )
pronouns_freetext = models.CharField(" ", max_length=30, null=True, blank=True, help_text="Optionally provide your personal pronouns. These will be displayed on your public profile page and alongside your name in Meetecho and, in future, other systems. Select any number of the checkboxes OR provide a custom string up to 30 characters.")
biography = models.TextField(blank=True, help_text="Short biography for use on leadership pages. Use plain text or reStructuredText markup.")
Expand Down
8 changes: 5 additions & 3 deletions ietf/person/tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -246,9 +246,11 @@ def test_cdn_photo_url_cdn_off(self):
self.assertNotIn('cdn-cgi/photo',p.cdn_photo_url())

def test_invalid_name_characters_rejected(self):
slash_person = PersonFactory.build(name='I have a /', user=None) # build() does not save the new object
with self.assertRaises(ValidationError):
slash_person.full_clean() # calls validators (save() does *not*)
for disallowed in "/:@":
# build() does not save the new object
person_with_bad_name = PersonFactory.build(name=f"I have a {disallowed}", user=None)
with self.assertRaises(ValidationError, msg=f"Name with a {disallowed} char should be rejected"):
person_with_bad_name.full_clean() # calls validators (save() does *not*)


class PersonUtilsTests(TestCase):
Expand Down

0 comments on commit d5009ee

Please sign in to comment.