mirror of
https://github.com/Novaloop-AG/element-x-android.git
synced 2026-11-02 21:32:34 +00:00
Open the user profile of a user id that contains a slash
A slash is valid in the local part of a user id, but in a permalink it also separates the identifier from an event id, so the SDK could not tell the two apart and the link fell back to opening matrix.to in a browser. Only a user id can start with an @, so recover it before handing the URI to the SDK, and only when the identifier really contains a slash so every other permalink keeps taking the same path.
This commit is contained in:
+20
@@ -8,11 +8,13 @@
|
|||||||
|
|
||||||
package io.element.android.libraries.matrix.impl.permalink
|
package io.element.android.libraries.matrix.impl.permalink
|
||||||
|
|
||||||
|
import android.net.Uri
|
||||||
import androidx.core.net.toUri
|
import androidx.core.net.toUri
|
||||||
import dev.zacsweers.metro.AppScope
|
import dev.zacsweers.metro.AppScope
|
||||||
import dev.zacsweers.metro.ContributesBinding
|
import dev.zacsweers.metro.ContributesBinding
|
||||||
import io.element.android.libraries.core.extensions.runCatchingExceptions
|
import io.element.android.libraries.core.extensions.runCatchingExceptions
|
||||||
import io.element.android.libraries.matrix.api.core.EventId
|
import io.element.android.libraries.matrix.api.core.EventId
|
||||||
|
import io.element.android.libraries.matrix.api.core.MatrixPatterns
|
||||||
import io.element.android.libraries.matrix.api.core.RoomAlias
|
import io.element.android.libraries.matrix.api.core.RoomAlias
|
||||||
import io.element.android.libraries.matrix.api.core.RoomId
|
import io.element.android.libraries.matrix.api.core.RoomId
|
||||||
import io.element.android.libraries.matrix.api.core.UserId
|
import io.element.android.libraries.matrix.api.core.UserId
|
||||||
@@ -51,6 +53,10 @@ class DefaultPermalinkParser(
|
|||||||
matrixToConverter.convert(uri) ?: return PermalinkData.FallbackLink(uri)
|
matrixToConverter.convert(uri) ?: return PermalinkData.FallbackLink(uri)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
matrixToUri.userIdWithSlash()?.let { userId ->
|
||||||
|
return PermalinkData.UserLink(userId = userId)
|
||||||
|
}
|
||||||
|
|
||||||
val result = runCatchingExceptions {
|
val result = runCatchingExceptions {
|
||||||
parseMatrixEntityFrom(matrixToUri.toString())
|
parseMatrixEntityFrom(matrixToUri.toString())
|
||||||
}.getOrNull()
|
}.getOrNull()
|
||||||
@@ -84,3 +90,17 @@ class DefaultPermalinkParser(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A slash is allowed in the local part of a user id, but it also separates an identifier from an
|
||||||
|
* event id in a permalink, so [parseMatrixEntityFrom] cannot tell the two apart. Only a user id can
|
||||||
|
* start with an `@`, so recover it here rather than letting the ambiguity reach the SDK.
|
||||||
|
*/
|
||||||
|
private fun Uri.userIdWithSlash(): UserId? {
|
||||||
|
val identifier = fragment
|
||||||
|
?.removePrefix("/")
|
||||||
|
?.substringBefore('?')
|
||||||
|
?: return null
|
||||||
|
if (!identifier.startsWith("@") || !identifier.contains('/')) return null
|
||||||
|
return identifier.takeIf { MatrixPatterns.isUserId(it) }?.let(::UserId)
|
||||||
|
}
|
||||||
|
|||||||
+44
@@ -0,0 +1,44 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2026 Element Creations Ltd.
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
|
||||||
|
* Please see LICENSE files in the repository root for full details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package io.element.android.libraries.matrix.impl.permalink
|
||||||
|
|
||||||
|
import com.google.common.truth.Truth.assertThat
|
||||||
|
import io.element.android.libraries.matrix.api.core.UserId
|
||||||
|
import io.element.android.libraries.matrix.api.permalink.PermalinkData
|
||||||
|
import io.element.android.tests.testutils.robolectric.RobolectricTest
|
||||||
|
import org.junit.Test
|
||||||
|
|
||||||
|
class DefaultPermalinkParserTest : RobolectricTest() {
|
||||||
|
@Test
|
||||||
|
fun `a matrix-to link to a user id with a slash is parsed as a user link`() {
|
||||||
|
val result = createParser().parse("https://matrix.to/#/@it/sme:matrix.org")
|
||||||
|
assertThat(result).isEqualTo(PermalinkData.UserLink(UserId("@it/sme:matrix.org")))
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `an escaped slash in a user id is parsed as a user link`() {
|
||||||
|
val result = createParser().parse("https://matrix.to/#/@it%2Fsme:matrix.org")
|
||||||
|
assertThat(result).isEqualTo(PermalinkData.UserLink(UserId("@it/sme:matrix.org")))
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `an element web link to a user id with a slash is parsed as a user link`() {
|
||||||
|
val result = createParser().parse("https://app.element.io/#/user/@it/sme:matrix.org")
|
||||||
|
assertThat(result).isEqualTo(PermalinkData.UserLink(UserId("@it/sme:matrix.org")))
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `a user id with a slash that is not a valid user id is not a user link`() {
|
||||||
|
val result = createParser().parse("https://example.org/foo/@it/sme")
|
||||||
|
assertThat(result).isInstanceOf(PermalinkData.FallbackLink::class.java)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun createParser() = DefaultPermalinkParser(
|
||||||
|
matrixToConverter = DefaultMatrixToConverter(),
|
||||||
|
)
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user