1717package io.element.android.libraries.matrix.impl.permalink
1818
1919import android.net.Uri
20- import android.net.UrlQuerySanitizer
2120import com.squareup.anvil.annotations.ContributesBinding
2221import io.element.android.libraries.di.AppScope
23- import io.element.android.libraries.matrix.api.core.MatrixPatterns
22+ import io.element.android.libraries.matrix.api.core.EventId
23+ import io.element.android.libraries.matrix.api.core.RoomId
24+ import io.element.android.libraries.matrix.api.core.UserId
2425import io.element.android.libraries.matrix.api.permalink.MatrixToConverter
2526import io.element.android.libraries.matrix.api.permalink.PermalinkData
2627import io.element.android.libraries.matrix.api.permalink.PermalinkParser
2728import kotlinx.collections.immutable.toImmutableList
28- import timber.log.Timber
29- import java.net.URLDecoder
29+ import org.matrix.rustcomponents.sdk.MatrixId
30+ import org.matrix.rustcomponents.sdk.parseMatrixEntityFrom
3031import javax.inject.Inject
3132
3233/* *
@@ -41,118 +42,45 @@ class DefaultPermalinkParser @Inject constructor(
4142) : PermalinkParser {
4243 /* *
4344 * Turns a uri string to a [PermalinkData].
45+ * https://github.com/matrix-org/matrix-doc/blob/master/proposals/1704-matrix.to-permalinks.md
4446 */
4547 override fun parse (uriString : String ): PermalinkData {
4648 val uri = Uri .parse(uriString)
47- return parse(uri)
48- }
49-
50- /* *
51- * Turns a uri to a [PermalinkData].
52- * https://github.com/matrix-org/matrix-doc/blob/master/proposals/1704-matrix.to-permalinks.md
53- */
54- override fun parse (uri : Uri ): PermalinkData {
5549 // the client or element-based domain permalinks (e.g. https://app.element.io/#/user/@chagai95:matrix.org) don't have the
5650 // mxid in the first param (like matrix.to does - https://matrix.to/#/@chagai95:matrix.org) but rather in the second after /user/ so /user/mxid
5751 // so convert URI to matrix.to to simplify parsing process
5852 val matrixToUri = matrixToConverter.convert(uri) ? : return PermalinkData .FallbackLink (uri)
5953
60- // We can't use uri.fragment as it is decoding to early and it will break the parsing
61- // of parameters that represents url (like signurl)
62- val fragment = matrixToUri.toString().substringAfter(" #" ) // uri.fragment
63- if (fragment.isEmpty()) {
64- return PermalinkData .FallbackLink (uri)
65- }
66- val safeFragment = fragment.substringBefore(' ?' )
67- val viaQueryParameters = fragment.getViaParameters()
68-
69- // we are limiting to 2 params
70- val params = safeFragment
71- .split(MatrixPatterns .SEP_REGEX )
72- .filter { it.isNotEmpty() }
73- .take(2 )
74-
75- val decodedParams = params
76- .map { URLDecoder .decode(it, " UTF-8" ) }
77-
78- val identifier = params.getOrNull(0 )
79- val decodedIdentifier = decodedParams.getOrNull(0 )
80- val extraParameter = decodedParams.getOrNull(1 )
81- return when {
82- identifier.isNullOrEmpty() || decodedIdentifier.isNullOrEmpty() -> PermalinkData .FallbackLink (uri)
83- MatrixPatterns .isUserId(decodedIdentifier) -> PermalinkData .UserLink (userId = decodedIdentifier)
84- MatrixPatterns .isRoomId(decodedIdentifier) -> {
85- handleRoomIdCase(fragment, decodedIdentifier, matrixToUri, extraParameter, viaQueryParameters)
86- }
87- MatrixPatterns .isRoomAlias(decodedIdentifier) -> {
88- PermalinkData .RoomLink (
89- roomIdOrAlias = decodedIdentifier,
90- isRoomAlias = true ,
91- eventId = extraParameter.takeIf { ! it.isNullOrEmpty() && MatrixPatterns .isEventId(it) },
92- viaParameters = viaQueryParameters.toImmutableList()
54+ val result = runCatching {
55+ parseMatrixEntityFrom(matrixToUri.toString())
56+ }.getOrNull()
57+ return if (result == null ) {
58+ PermalinkData .FallbackLink (uri)
59+ } else {
60+ val viaParameters = result.via.toImmutableList()
61+ when (val id = result.id) {
62+ is MatrixId .Room -> PermalinkData .RoomIdLink (
63+ roomId = RoomId (id.id),
64+ viaParameters = viaParameters,
9365 )
94- }
95- else -> PermalinkData .FallbackLink (uri, MatrixPatterns .isGroupId(identifier))
96- }
97- }
98-
99- private fun handleRoomIdCase (fragment : String , identifier : String , uri : Uri , extraParameter : String? , viaQueryParameters : List <String >): PermalinkData {
100- // Can't rely on built in parsing because it's messing around the signurl
101- val paramList = safeExtractParams(fragment)
102- val signUrl = paramList.firstOrNull { it.first == " signurl" }?.second
103- val email = paramList.firstOrNull { it.first == " email" }?.second
104- return if (signUrl.isNullOrEmpty().not () && email.isNullOrEmpty().not ()) {
105- try {
106- val signValidUri = Uri .parse(signUrl)
107- val identityServerHost = signValidUri.authority ? : throw IllegalArgumentException (" missing `authority`" )
108- val token = signValidUri.getQueryParameter(" token" ) ? : throw IllegalArgumentException (" missing `token`" )
109- val privateKey = signValidUri.getQueryParameter(" private_key" ) ? : throw IllegalArgumentException (" missing `private_key`" )
110- PermalinkData .RoomEmailInviteLink (
111- roomId = identifier,
112- email = email!! ,
113- signUrl = signUrl!! ,
114- roomName = paramList.firstOrNull { it.first == " room_name" }?.second,
115- inviterName = paramList.firstOrNull { it.first == " inviter_name" }?.second,
116- roomAvatarUrl = paramList.firstOrNull { it.first == " room_avatar_url" }?.second,
117- roomType = paramList.firstOrNull { it.first == " room_type" }?.second,
118- identityServer = identityServerHost,
119- token = token,
120- privateKey = privateKey
66+ is MatrixId .User -> PermalinkData .UserLink (
67+ userId = UserId (id.id),
68+ )
69+ is MatrixId .RoomAlias -> PermalinkData .RoomAliasLink (
70+ roomAlias = id.alias,
71+ viaParameters = viaParameters,
72+ )
73+ is MatrixId .EventOnRoomId -> PermalinkData .EventIdLink (
74+ roomId = RoomId (id.roomId),
75+ eventId = EventId (id.eventId),
76+ viaParameters = viaParameters,
77+ )
78+ is MatrixId .EventOnRoomAlias -> PermalinkData .EventIdAliasLink (
79+ roomAlias = id.alias,
80+ eventId = EventId (id.eventId),
81+ viaParameters = viaParameters,
12182 )
122- } catch (failure: Throwable ) {
123- Timber .i(" ## Permalink: Failed to parse permalink $signUrl " )
124- PermalinkData .FallbackLink (uri)
125- }
126- } else {
127- PermalinkData .RoomLink (
128- roomIdOrAlias = identifier,
129- isRoomAlias = false ,
130- eventId = extraParameter.takeIf { ! it.isNullOrEmpty() && MatrixPatterns .isEventId(it) },
131- viaParameters = viaQueryParameters.toImmutableList()
132- )
133- }
134- }
135-
136- private fun safeExtractParams (fragment : String ) =
137- fragment.substringAfter(" ?" ).split(' &' ).mapNotNull {
138- val splitNameValue = it.split(" =" )
139- if (splitNameValue.size == 2 ) {
140- Pair (splitNameValue[0 ], URLDecoder .decode(splitNameValue[1 ], " UTF-8" ))
141- } else {
142- null
14383 }
14484 }
145-
146- private fun String.getViaParameters (): List <String > {
147- return runCatching {
148- UrlQuerySanitizer (this )
149- .parameterList
150- .filter {
151- it.mParameter == " via"
152- }
153- .map {
154- URLDecoder .decode(it.mValue, " UTF-8" )
155- }
156- }.getOrDefault(emptyList())
15785 }
15886}
0 commit comments