diff --git a/zds/member/validators.py b/zds/member/validators.py index e959bcac66..6140deeb78 100644 --- a/zds/member/validators.py +++ b/zds/member/validators.py @@ -4,7 +4,7 @@ from django.utils.encoding import force_str from django.utils.translation import gettext_lazy as _ -from zds.utils.misc import contains_utf8mb4 +from zds.utils.misc import contains_utf8mb4, remove_utf8mb4 from zds.member.models import BannedEmailProvider, Profile @@ -70,6 +70,15 @@ def __call__(self, value, check_username_available=True): validate_zds_email = ZdSEmailValidator() +def clean_username_social_auth(username): + """ + Clean username of accounts created using social auth. + """ + # These three conditions are the same as the first three in the "validate_zds_username" function below. + # If you modify one of them here, make sure you do the same there! + return remove_utf8mb4(username).replace(",", "").replace("/", "") + + def validate_zds_username(value, check_username_available=True): """ Check if username is used by another user @@ -88,6 +97,9 @@ def validate_zds_username(value, check_username_available=True): msg = None user_count = User.objects.filter(username=value).count() skeleton_user_count = Profile.objects.filter(username_skeleton=Profile.find_username_skeleton(value)).count() + + # These first three conditions are the same as those in the "clean_username_social_auth" function above. + # If you modify one of them here, make sure you do the same there! if "," in value: msg = _("Le nom d'utilisateur ne peut contenir de virgules") elif "/" in value: diff --git a/zds/settings/abstract_base/requirements.py b/zds/settings/abstract_base/requirements.py index 75a3981238..9294562e50 100644 --- a/zds/settings/abstract_base/requirements.py +++ b/zds/settings/abstract_base/requirements.py @@ -10,9 +10,12 @@ social_auth_config = config.get("social_auth", {}) +SOCIAL_AUTH_CLEAN_USERNAME_FUNCTION = "zds.member.validators.clean_username_social_auth" + SOCIAL_AUTH_RAISE_EXCEPTIONS = False SOCIAL_AUTH_FACEBOOK_SCOPE = ["email"] +SOCIAL_AUTH_FACEBOOK_PROFILE_EXTRA_PARAMS = {"fields": "name,email"} SOCIAL_AUTH_PIPELINE = ( "social_core.pipeline.social_auth.social_details", diff --git a/zds/utils/misc.py b/zds/utils/misc.py index 60e6d39fc5..29899c2ad7 100644 --- a/zds/utils/misc.py +++ b/zds/utils/misc.py @@ -49,14 +49,21 @@ def convert_camel_to_underscore(camel_case): return re.sub("([a-z0-9])([A-Z])", r"\1_\2", s1).lower() -def contains_utf8mb4(s): +def remove_utf8mb4(s): """ - This string contains at least one character of more than 3 bytes + Remove characters of more than 3 bytes. """ if not isinstance(s, str): s = str(s, "utf-8") re_pattern = re.compile("[^\u0000-\uD7FF\uE000-\uFFFF]", re.UNICODE) - return s != re_pattern.sub("\uFFFD", s) + return re_pattern.sub("", s) + + +def contains_utf8mb4(s): + """ + Check if this string contains at least one character of more than 3 bytes. + """ + return s != remove_utf8mb4(s) def check_essential_accounts(): diff --git a/zds/utils/tests/test_misc.py b/zds/utils/tests/test_misc.py index b33b0c268b..f97055def5 100644 --- a/zds/utils/tests/test_misc.py +++ b/zds/utils/tests/test_misc.py @@ -3,13 +3,21 @@ from django.test import TestCase from zds.member.tests.factories import ProfileFactory, StaffProfileFactory, UserFactory from zds.tutorialv2.tests.factories import PublishedContentFactory -from zds.utils.misc import contains_utf8mb4, check_essential_accounts +from zds.utils.misc import contains_utf8mb4, check_essential_accounts, remove_utf8mb4 from zds.utils.models import Alert from zds.utils.context_processor import get_header_notifications class Misc(TestCase): - def test_utf8mb4(self): + def test_remove_utf8mb4(self): + self.assertEqual("abc", remove_utf8mb4("abc")) + self.assertEqual("abc", remove_utf8mb4("abc")) + self.assertEqual("abc€", remove_utf8mb4("abc€")) + self.assertEqual("abc€", remove_utf8mb4("abc€")) + self.assertEqual("atbc€", remove_utf8mb4("a🐙tbc€")) + self.assertEqual("atbc€", remove_utf8mb4("a🐙tbc€")) + + def test_contains_utf8mb4(self): self.assertFalse(contains_utf8mb4("abc")) self.assertFalse(contains_utf8mb4("abc")) self.assertFalse(contains_utf8mb4("abc€"))