From 9703365830c5f9ae26fd431bc4eb1acb2607971d Mon Sep 17 00:00:00 2001 From: Andy Uhnak Date: Mon, 28 Mar 2022 15:42:23 +0100 Subject: [PATCH 1/3] Enable joining a room via identifier from another home server --- Riot/Modules/Application/LegacyAppDelegate.m | 32 +++-------- .../Home/GroupHomeViewController.m | 5 +- .../MXRoomAliasResolution+Deeplink.swift | 38 +++++++++++++ .../MXRoomAliasResolutionDeeplinkTests.swift | 56 +++++++++++++++++++ changelog.d/4858.bugfix | 1 + 5 files changed, 106 insertions(+), 26 deletions(-) create mode 100644 Riot/Modules/DeepLink/MXRoomAliasResolution+Deeplink.swift create mode 100644 RiotTests/Modules/DeepLink/MXRoomAliasResolutionDeeplinkTests.swift create mode 100644 changelog.d/4858.bugfix diff --git a/Riot/Modules/Application/LegacyAppDelegate.m b/Riot/Modules/Application/LegacyAppDelegate.m index 49e2b2c9a..c30629d60 100644 --- a/Riot/Modules/Application/LegacyAppDelegate.m +++ b/Riot/Modules/Application/LegacyAppDelegate.m @@ -1481,7 +1481,7 @@ NSString *const AppDelegateUniversalLinkDidChangeNotification = @"AppDelegateUni // Ask the HS to resolve the room alias into a room id and then retry self->universalLinkFragmentPending = fragment; MXKAccount* account = accountManager.activeAccounts.firstObject; - [account.mxSession.matrixRestClient roomIDForRoomAlias:roomIdOrAlias success:^(NSString *roomId) { + [account.mxSession.matrixRestClient resolveRoomAlias:roomIdOrAlias success:^(MXRoomAliasResolution *resolution) { // Note: the activity indicator will not disappear if the session is not ready [homeViewController stopActivityIndicator]; @@ -1489,34 +1489,20 @@ NSString *const AppDelegateUniversalLinkDidChangeNotification = @"AppDelegateUni // Check that 'fragment' has not been cancelled if ([self->universalLinkFragmentPending isEqualToString:fragment]) { - // Retry opening the link but with the returned room id - NSString *newUniversalLinkFragment = - [fragment stringByReplacingOccurrencesOfString:[MXTools encodeURIComponent:roomIdOrAlias] - withString:[MXTools encodeURIComponent:roomId] - ]; - - // The previous operation can fail because of percent encoding - // TBH we are not clean on data inputs. For the moment, just give another try with no encoding - // TODO: Have a dedicated module and tests to handle universal links (matrix.to, email link, etc) - if ([newUniversalLinkFragment isEqualToString:fragment]) + NSString *mewFragment = resolution.deeplinkFragment; + if (mewFragment && ![mewFragment isEqualToString:fragment]) { - newUniversalLinkFragment = - [fragment stringByReplacingOccurrencesOfString:roomIdOrAlias - withString:[MXTools encodeURIComponent:roomId]]; - } - - if (![newUniversalLinkFragment isEqualToString:fragment]) - { - self->universalLinkFragmentPendingRoomAlias = @{roomId: roomIdOrAlias}; - - UniversalLinkParameters *newParameters = [[UniversalLinkParameters alloc] initWithFragment:newUniversalLinkFragment universalLinkURL:universalLinkURL presentationParameters:presentationParameters]; - + self->universalLinkFragmentPendingRoomAlias = @{resolution.roomId: roomIdOrAlias}; + + UniversalLinkParameters *newParameters = [[UniversalLinkParameters alloc] initWithFragment:mewFragment + universalLinkURL:universalLinkURL + presentationParameters:presentationParameters]; [self handleUniversalLinkWithParameters:newParameters]; } else { // Do not continue. Else we will loop forever - MXLogDebug(@"[AppDelegate] Universal link: Error: Cannot resolve alias in %@ to the room id %@", fragment, roomId); + MXLogDebug(@"[AppDelegate] Universal link: Error: Cannot resolve alias in %@ to the room id %@", fragment, resolution.roomId); } } diff --git a/Riot/Modules/Communities/Home/GroupHomeViewController.m b/Riot/Modules/Communities/Home/GroupHomeViewController.m index d8a9e3ed3..18971b51d 100644 --- a/Riot/Modules/Communities/Home/GroupHomeViewController.m +++ b/Riot/Modules/Communities/Home/GroupHomeViewController.m @@ -867,14 +867,13 @@ __weak typeof(self) weakSelf = self; [self startActivityIndicator]; - [self.mxSession.matrixRestClient roomIDForRoomAlias:roomIdOrAlias success:^(NSString *roomId) { - + [self.mxSession.matrixRestClient resolveRoomAlias:roomIdOrAlias success:^(MXRoomAliasResolution *resolution) { if (roomId && weakSelf) { typeof(self) self = weakSelf; [self stopActivityIndicator]; - [self didSelectRoomId:roomId]; + [self didSelectRoomId:resolution.roomId]; } } failure:^(NSError *error) { diff --git a/Riot/Modules/DeepLink/MXRoomAliasResolution+Deeplink.swift b/Riot/Modules/DeepLink/MXRoomAliasResolution+Deeplink.swift new file mode 100644 index 000000000..8c107fc65 --- /dev/null +++ b/Riot/Modules/DeepLink/MXRoomAliasResolution+Deeplink.swift @@ -0,0 +1,38 @@ +// +// Copyright 2022 New Vector Ltd +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +import Foundation +import MatrixSDK + +@objc extension MXRoomAliasResolution { + + /// Deeplink fragment using a room identifier and a list of servers aware of this identifier + /// + /// For more details see + /// https://github.com/matrix-org/matrix-spec-proposals/blob/old_master/proposals/1704-matrix.to-permalinks.md + var deeplinkFragment: String? { + guard let roomId = roomId else { + MXLog.debug("[MXRoomAliasResolution]: Missing room identifier") + return nil + } + + guard let servers = servers, !servers.isEmpty else { + return roomId + } + + return roomId + "?via=" + servers.joined(separator: "&via=") + } +} diff --git a/RiotTests/Modules/DeepLink/MXRoomAliasResolutionDeeplinkTests.swift b/RiotTests/Modules/DeepLink/MXRoomAliasResolutionDeeplinkTests.swift new file mode 100644 index 000000000..150673f39 --- /dev/null +++ b/RiotTests/Modules/DeepLink/MXRoomAliasResolutionDeeplinkTests.swift @@ -0,0 +1,56 @@ +// +// Copyright 2022 New Vector Ltd +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +import Foundation +import XCTest +@testable import Riot + +class MXRoomAliasResolutionDeeplinkTests: XCTestCase { + func test_fragmentIsNilForInvalidResolution() { + let resolution = MXRoomAliasResolution() + XCTAssertNil(resolution.deeplinkFragment) + } + + func test_fragmentDoesNotContainServers_ifNoServers() { + let resolution = MXRoomAliasResolution() + resolution.roomId = "!abc:matrix.org" + + XCTAssertEqual(resolution.deeplinkFragment, "!abc:matrix.org") + } + + func test_fragmentContainsSingleServer() { + let resolution = MXRoomAliasResolution() + resolution.roomId = "xyz:element.io" + resolution.servers = [ + "matrix.org" + ] + + XCTAssertEqual(resolution.deeplinkFragment, "xyz:element.io?via=matrix.org") + } + + func test_fragmentContainsMultipleSerivers() { + let resolution = MXRoomAliasResolution() + resolution.roomId = "mno:server.com" + resolution.servers = [ + "server.com", + "element.io", + "wikipedia.org", + "matrix.org" + ] + + XCTAssertEqual(resolution.deeplinkFragment, "mno:server.com?via=server.com&via=element.io&via=wikipedia.org&via=matrix.org") + } +} diff --git a/changelog.d/4858.bugfix b/changelog.d/4858.bugfix new file mode 100644 index 000000000..2a7d342e8 --- /dev/null +++ b/changelog.d/4858.bugfix @@ -0,0 +1 @@ +Room: Enable joining a room via identifier from another home server From a8eb85546f491ce4222d5776fa6b34d9be39f792 Mon Sep 17 00:00:00 2001 From: Andy Uhnak Date: Mon, 28 Mar 2022 16:44:24 +0100 Subject: [PATCH 2/3] Typo --- Riot/Modules/Application/LegacyAppDelegate.m | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Riot/Modules/Application/LegacyAppDelegate.m b/Riot/Modules/Application/LegacyAppDelegate.m index c30629d60..74fa743b7 100644 --- a/Riot/Modules/Application/LegacyAppDelegate.m +++ b/Riot/Modules/Application/LegacyAppDelegate.m @@ -1489,12 +1489,12 @@ NSString *const AppDelegateUniversalLinkDidChangeNotification = @"AppDelegateUni // Check that 'fragment' has not been cancelled if ([self->universalLinkFragmentPending isEqualToString:fragment]) { - NSString *mewFragment = resolution.deeplinkFragment; - if (mewFragment && ![mewFragment isEqualToString:fragment]) + NSString *newFragment = resolution.deeplinkFragment; + if (newFragment && ![newFragment isEqualToString:fragment]) { self->universalLinkFragmentPendingRoomAlias = @{resolution.roomId: roomIdOrAlias}; - UniversalLinkParameters *newParameters = [[UniversalLinkParameters alloc] initWithFragment:mewFragment + UniversalLinkParameters *newParameters = [[UniversalLinkParameters alloc] initWithFragment:newFragment universalLinkURL:universalLinkURL presentationParameters:presentationParameters]; [self handleUniversalLinkWithParameters:newParameters]; From 064bfc20759ab2fcb7fa373a093680ce0fbc098a Mon Sep 17 00:00:00 2001 From: Andy Uhnak Date: Mon, 28 Mar 2022 16:55:54 +0100 Subject: [PATCH 3/3] URL encode fragment deeplink --- Riot/Modules/DeepLink/MXRoomAliasResolution+Deeplink.swift | 7 ++++++- .../DeepLink/MXRoomAliasResolutionDeeplinkTests.swift | 6 +++--- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/Riot/Modules/DeepLink/MXRoomAliasResolution+Deeplink.swift b/Riot/Modules/DeepLink/MXRoomAliasResolution+Deeplink.swift index 8c107fc65..234f07849 100644 --- a/Riot/Modules/DeepLink/MXRoomAliasResolution+Deeplink.swift +++ b/Riot/Modules/DeepLink/MXRoomAliasResolution+Deeplink.swift @@ -29,10 +29,15 @@ import MatrixSDK return nil } + return MXTools.encodeURIComponent( + fragment(for: roomId) + ) + } + + private func fragment(for roomId: String) -> String { guard let servers = servers, !servers.isEmpty else { return roomId } - return roomId + "?via=" + servers.joined(separator: "&via=") } } diff --git a/RiotTests/Modules/DeepLink/MXRoomAliasResolutionDeeplinkTests.swift b/RiotTests/Modules/DeepLink/MXRoomAliasResolutionDeeplinkTests.swift index 150673f39..c465dad67 100644 --- a/RiotTests/Modules/DeepLink/MXRoomAliasResolutionDeeplinkTests.swift +++ b/RiotTests/Modules/DeepLink/MXRoomAliasResolutionDeeplinkTests.swift @@ -28,7 +28,7 @@ class MXRoomAliasResolutionDeeplinkTests: XCTestCase { let resolution = MXRoomAliasResolution() resolution.roomId = "!abc:matrix.org" - XCTAssertEqual(resolution.deeplinkFragment, "!abc:matrix.org") + XCTAssertEqual(resolution.deeplinkFragment, "!abc%3Amatrix.org") } func test_fragmentContainsSingleServer() { @@ -38,7 +38,7 @@ class MXRoomAliasResolutionDeeplinkTests: XCTestCase { "matrix.org" ] - XCTAssertEqual(resolution.deeplinkFragment, "xyz:element.io?via=matrix.org") + XCTAssertEqual(resolution.deeplinkFragment, "xyz%3Aelement.io%3Fvia%3Dmatrix.org") } func test_fragmentContainsMultipleSerivers() { @@ -51,6 +51,6 @@ class MXRoomAliasResolutionDeeplinkTests: XCTestCase { "matrix.org" ] - XCTAssertEqual(resolution.deeplinkFragment, "mno:server.com?via=server.com&via=element.io&via=wikipedia.org&via=matrix.org") + XCTAssertEqual(resolution.deeplinkFragment, "mno%3Aserver.com%3Fvia%3Dserver.com%26via%3Delement.io%26via%3Dwikipedia.org%26via%3Dmatrix.org") } }