From 93857b85f830e6ad5bd09d10ff86c8fadcd2fb87 Mon Sep 17 00:00:00 2001 From: Kara Engelhardt Date: Wed, 14 Jan 2026 17:35:00 +0100 Subject: [PATCH] =?UTF-8?q?=F0=9F=90=9B=20Handle=20unicode=20characters=20?= =?UTF-8?q?when=20redacting=20email=20attachment=20filenames?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- froide/account/services.py | 12 +++++++++++- froide/account/tests/test_account.py | 10 ++++++++++ froide/foirequest/services.py | 4 +++- 3 files changed, 24 insertions(+), 2 deletions(-) diff --git a/froide/account/services.py b/froide/account/services.py index ac5f1f91d..2ee9770a3 100644 --- a/froide/account/services.py +++ b/froide/account/services.py @@ -1,6 +1,7 @@ import hashlib import hmac import re +import unicodedata from datetime import timedelta from typing import Dict, Optional from urllib.parse import urlencode @@ -313,7 +314,7 @@ def check_against_blocklist(cls, user, save=True) -> bool: user.save() return blocklisted - def apply_name_redaction(self, content, replacement=""): + def apply_name_redaction(self, content, replacement="", unicode=True): if not self.user.private: return content @@ -328,6 +329,15 @@ def apply_name_redaction(self, content, replacement=""): *self.user.first_name.split(), *self.user.last_name.split(), ] + + if not unicode: + user_asciiish_name = ( + unicodedata.normalize("NFKD", self.user.get_full_name()) + .encode("ascii", "ignore") + .decode() + ) + needles.extend(user_asciiish_name.split()) + if self.user.organization_name: needles.append(self.user.organization_name) diff --git a/froide/account/tests/test_account.py b/froide/account/tests/test_account.py index 11958d541..0067e1453 100644 --- a/froide/account/tests/test_account.py +++ b/froide/account/tests/test_account.py @@ -854,3 +854,13 @@ def test_multipart_name_redaction(): repl = "NAME" redacted_name = account_service.apply_name_redaction(name, repl) assert redacted_name == "Reply-NAME-NAME-NAME.pdf" + + +@pytest.mark.django_db +def test_unicode_name_redaction(): + user = User.objects.create(first_name="Älex", last_name="Eğçamplé", private=True) + account_service = AccountService(user) + name = "reply-alex-egcample.pdf" + repl = "NAME" + redacted_name = account_service.apply_name_redaction(name, repl, unicode=False) + assert redacted_name == "reply-NAME-NAME.pdf" diff --git a/froide/foirequest/services.py b/froide/foirequest/services.py index 548b1276e..0ac54dc56 100644 --- a/froide/foirequest/services.py +++ b/froide/foirequest/services.py @@ -527,7 +527,9 @@ def add_attachments(self, foirequest, message, attachments): # Translators: replacement for person name in filename repl = str(_("NAME")) - att.name = account_service.apply_name_redaction(att.name, repl) + att.name = account_service.apply_name_redaction( + att.name, repl, unicode=False + ) att.name = re.sub(r"[^A-Za-z0-9_\.\-]", "", att.name) att.name = att.name[:250]