From ff89302cf5e39fbe3cc8213ab005f4d5a9b49a0a Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Wed, 19 Aug 2026 11:56:34 +0200 Subject: [PATCH] Normalize the applicationName used in user agent, as HTTP spec does not allow UTF-8 chars in headers. --- .../libraries/core/extensions/BasicExtensions.kt | 12 ++++++++++++ .../libraries/core/extensions/BasicExtensionsTest.kt | 6 ++++++ .../network/useragent/DefaultUserAgentProvider.kt | 5 +++-- 3 files changed, 21 insertions(+), 2 deletions(-) diff --git a/libraries/core/src/main/kotlin/io/element/android/libraries/core/extensions/BasicExtensions.kt b/libraries/core/src/main/kotlin/io/element/android/libraries/core/extensions/BasicExtensions.kt index fe563138ad..87d6350c65 100644 --- a/libraries/core/src/main/kotlin/io/element/android/libraries/core/extensions/BasicExtensions.kt +++ b/libraries/core/src/main/kotlin/io/element/android/libraries/core/extensions/BasicExtensions.kt @@ -8,6 +8,7 @@ package io.element.android.libraries.core.extensions +import java.text.Normalizer import java.util.Locale fun Boolean.toOnOff() = if (this) "ON" else "OFF" @@ -114,3 +115,14 @@ fun String.toSafeLength( this } } + +/** + * Remove accents and replace special characters by ASCII from the string. + * For instance, "é" will be replaced by "e", "ç" by "c", etc. + */ +fun String.normalized(): String { + // Normalize the string. + return Normalizer.normalize(this, Normalizer.Form.NFD) + // then keep only ASCII characters and replace non-ASCII characters with an empty string. + .replace("[^\\p{ASCII}]".toRegex(), "") +} diff --git a/libraries/core/src/test/kotlin/io/element/android/libraries/core/extensions/BasicExtensionsTest.kt b/libraries/core/src/test/kotlin/io/element/android/libraries/core/extensions/BasicExtensionsTest.kt index 0099a67a79..c3cae14843 100644 --- a/libraries/core/src/test/kotlin/io/element/android/libraries/core/extensions/BasicExtensionsTest.kt +++ b/libraries/core/src/test/kotlin/io/element/android/libraries/core/extensions/BasicExtensionsTest.kt @@ -74,4 +74,10 @@ class BasicExtensionsTest { val result = textWithDirectionOverrides.filterDirectionOverrides() assertEquals("123456789", result) } + + @Test + fun `normalized removes accents and replace special characters from text`() { + assertEquals("Stefan", "Ștefan".normalized()) + assertEquals("ca enleve etre", "ça enlève être".normalized()) + } } diff --git a/libraries/network/src/main/kotlin/io/element/android/libraries/network/useragent/DefaultUserAgentProvider.kt b/libraries/network/src/main/kotlin/io/element/android/libraries/network/useragent/DefaultUserAgentProvider.kt index 3ecd091e0d..2a32c6d273 100644 --- a/libraries/network/src/main/kotlin/io/element/android/libraries/network/useragent/DefaultUserAgentProvider.kt +++ b/libraries/network/src/main/kotlin/io/element/android/libraries/network/useragent/DefaultUserAgentProvider.kt @@ -12,6 +12,7 @@ import android.os.Build import dev.zacsweers.metro.AppScope import dev.zacsweers.metro.ContributesBinding import dev.zacsweers.metro.SingleIn +import io.element.android.libraries.core.extensions.normalized import io.element.android.libraries.core.meta.BuildMeta import io.element.android.libraries.matrix.api.SdkMetadata @@ -26,11 +27,11 @@ class DefaultUserAgentProvider( override fun provide(): String = userAgent /** - * Create an user agent with the application version. + * Create a user agent with the application version. * Ex: Element X/1.5.0 (Xiaomi Mi 9T; Android 11; RKQ1.200826.002; Sdk c344b155c) */ private fun buildUserAgent(): String { - val appName = buildMeta.applicationName + val appName = buildMeta.applicationName.normalized() val appVersion = buildMeta.versionName val deviceManufacturer = Build.MANUFACTURER val deviceModel = Build.MODEL