From f398c7f926ef51c88adc5c4609626e51ec5da411 Mon Sep 17 00:00:00 2001 From: Doug Date: Wed, 3 Aug 2022 11:40:43 +0100 Subject: [PATCH] Fix an infinite loop when tapping an unjoined room alias. --- Riot/Modules/Application/LegacyAppDelegate.m | 21 +++++------------ .../Common/Recents/RecentsViewController.m | 10 ++++---- Riot/Modules/Room/RoomViewController.m | 7 +++--- Riot/Utils/UniversalLink.h | 5 ++++ Riot/Utils/UniversalLink.m | 23 +++++++++++++++---- changelog.d/6492.bugfix | 1 + 6 files changed, 40 insertions(+), 27 deletions(-) create mode 100644 changelog.d/6492.bugfix diff --git a/Riot/Modules/Application/LegacyAppDelegate.m b/Riot/Modules/Application/LegacyAppDelegate.m index cbaeaa4970..032e25dced 100644 --- a/Riot/Modules/Application/LegacyAppDelegate.m +++ b/Riot/Modules/Application/LegacyAppDelegate.m @@ -1296,8 +1296,6 @@ - (BOOL)handleUniversalLinkWithParameters:(UniversalLinkParameters*)universalLin BOOL continueUserActivity = NO; MXKAccountManager *accountManager = [MXKAccountManager sharedManager]; - MXLogDebug(@"[AppDelegate] Universal link: handleUniversalLinkFragment: %@", fragment); - // Make sure we have plain utf8 character for separators fragment = [fragment stringByRemovingPercentEncoding]; MXLogDebug(@"[AppDelegate] Universal link: handleUniversalLinkFragment: %@", fragment); @@ -1313,17 +1311,8 @@ - (BOOL)handleUniversalLinkWithParameters:(UniversalLinkParameters*)universalLin // Sanity check if (!pathParams.count) { - // Handle simple room links with aliases/identifiers as UniversalLink will not parse these. - NSString* absoluteUrl = [universalLink.url.absoluteString stringByRemovingPercentEncoding]; - if ([MXTools isMatrixRoomAlias:absoluteUrl] - || [MXTools isMatrixRoomIdentifier:absoluteUrl]) - { - pathParams = @[absoluteUrl]; - } - else { - MXLogDebug(@"[AppDelegate] Universal link: Error: No path parameters"); - return NO; - } + MXLogFailure(@"[AppDelegate] Universal link: Error: No path parameters"); + return NO; } NSString *roomIdOrAlias; @@ -1499,9 +1488,11 @@ - (BOOL)handleUniversalLinkWithParameters:(UniversalLinkParameters*)universalLin if (newFragment && ![newFragment isEqualToString:fragment]) { self->universalLinkFragmentPendingRoomAlias = @{resolution.roomId: roomIdOrAlias}; - + + // Create a new link with the updated fragment, otherwise we loop back round resolving the room ID infinitely. + UniversalLink *newLink = [[UniversalLink alloc] initWithUrl:universalLink.url updatedFragment:newFragment]; UniversalLinkParameters *newParameters = [[UniversalLinkParameters alloc] initWithFragment:newFragment - universalLink:universalLink + universalLink:newLink presentationParameters:presentationParameters]; [self handleUniversalLinkWithParameters:newParameters]; } diff --git a/Riot/Modules/Common/Recents/RecentsViewController.m b/Riot/Modules/Common/Recents/RecentsViewController.m index ca12ed43e7..3edd164281 100644 --- a/Riot/Modules/Common/Recents/RecentsViewController.m +++ b/Riot/Modules/Common/Recents/RecentsViewController.m @@ -1602,11 +1602,11 @@ - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath if (roomIdOrAlias.length) { - // Open the room or preview it - NSString *fragment = [NSString stringWithFormat:@"/room/%@", [MXTools encodeURIComponent:roomIdOrAlias]]; - NSURL *url = [NSURL URLWithString:[MXTools permalinkToRoom:fragment]]; - UniversalLink *link = [[UniversalLink alloc] initWithUrl:url]; - [[AppDelegate theDelegate] handleUniversalLinkFragment:fragment fromLink:link]; + // Create a permalink to open or preview the room. + NSString *permalink = [MXTools permalinkToRoom:roomIdOrAlias]; + NSURL *permalinkURL = [NSURL URLWithString:permalink]; + UniversalLink *link = [[UniversalLink alloc] initWithUrl:permalinkURL]; + [[AppDelegate theDelegate] handleUniversalLinkFragment:permalinkURL.fragment fromLink:link]; } [tableView deselectRowAtIndexPath:indexPath animated:NO]; } diff --git a/Riot/Modules/Room/RoomViewController.m b/Riot/Modules/Room/RoomViewController.m index cf4b80b8c5..bfcaa0df6a 100644 --- a/Riot/Modules/Room/RoomViewController.m +++ b/Riot/Modules/Room/RoomViewController.m @@ -4279,10 +4279,11 @@ - (BOOL)dataSource:(MXKDataSource *)dataSource shouldDoAction:(NSString *)action NSString *roomIdOrAlias = absoluteURLString; - // Open the room or preview it - NSString *fragment = [NSString stringWithFormat:@"/room/%@", [MXTools encodeURIComponent:roomIdOrAlias]]; + // Create a permalink to open or preview the room. + NSString *permalink = [MXTools permalinkToRoom:roomIdOrAlias]; + NSURL *permalinkURL = [NSURL URLWithString:permalink]; - [self handleUniversalLinkFragment:fragment fromURL:url]; + [self handleUniversalLinkFragment:permalinkURL.fragment fromURL:permalinkURL]; } // Preview the clicked group else if ([MXTools isMatrixGroupIdentifier:absoluteURLString]) diff --git a/Riot/Utils/UniversalLink.h b/Riot/Utils/UniversalLink.h index bb7c629526..a5ea787635 100644 --- a/Riot/Utils/UniversalLink.h +++ b/Riot/Utils/UniversalLink.h @@ -40,6 +40,11 @@ NS_ASSUME_NONNULL_BEGIN /// @param url original url - (id)initWithUrl:(NSURL *)url; +/// An Initializer that preserves the original URL, but parses the parameters from an updated fragment. +/// @param url original url +/// @param fragment the updated fragment to parse. +- (id)initWithUrl:(NSURL *)url updatedFragment:(NSString *)fragment; + @end NS_ASSUME_NONNULL_END diff --git a/Riot/Utils/UniversalLink.m b/Riot/Utils/UniversalLink.m index edd73c7b85..98d3802dfb 100644 --- a/Riot/Utils/UniversalLink.m +++ b/Riot/Utils/UniversalLink.m @@ -27,7 +27,22 @@ - (id)initWithUrl:(NSURL *)url _url = url; // Extract required parameters from the link - [self parsePathAndQueryParams]; + [self parsePathAndQueryParamsForURL:url]; + } + return self; +} + +- (id)initWithUrl:(NSURL *)url updatedFragment:(NSString *)fragment +{ + self = [super init]; + if (self) + { + _url = url; + + // Update the url with the fragment + NSURLComponents *components = [[NSURLComponents alloc] initWithURL:url resolvingAgainstBaseURL:NO]; + components.fragment = fragment; + [self parsePathAndQueryParamsForURL:components.URL]; } return self; } @@ -38,12 +53,12 @@ Extract params from the URL fragment part (after '#') of a vector.im Universal l The fragment can contain a '?'. So there are two kinds of parameters: path params and query params. It is in the form of /[pathParam1]/[pathParam2]?[queryParam1Key]=[queryParam1Value]&[queryParam2Key]=[queryParam2Value] */ -- (void)parsePathAndQueryParams +- (void)parsePathAndQueryParamsForURL:(NSURL *)url { NSArray *pathParams; NSMutableDictionary *queryParams = [NSMutableDictionary dictionary]; - NSArray *fragments = [_url.fragment componentsSeparatedByString:@"?"]; + NSArray *fragments = [url.fragment componentsSeparatedByString:@"?"]; // Extract path params pathParams = [[fragments[0] stringByRemovingPercentEncoding] componentsSeparatedByString:@"/"]; @@ -57,7 +72,7 @@ - (void)parsePathAndQueryParams }]; // Extract query params - NSURLComponents *components = [NSURLComponents componentsWithURL:_url resolvingAgainstBaseURL:NO]; + NSURLComponents *components = [NSURLComponents componentsWithURL:url resolvingAgainstBaseURL:NO]; for (NSURLQueryItem *item in components.queryItems) { if (item.value) diff --git a/changelog.d/6492.bugfix b/changelog.d/6492.bugfix new file mode 100644 index 0000000000..563447802d --- /dev/null +++ b/changelog.d/6492.bugfix @@ -0,0 +1 @@ +Universal Links: Fix an infinite loop when handling a universal link for an unjoined room (or in some cases a crash).