Skip to content

Commit

Permalink
Fix an infinite loop when tapping an unjoined room alias. (#6522)
Browse files Browse the repository at this point in the history
* Fix a crash in universal link handling.
* Fix an infinite loop when tapping an unjoined room alias.
  • Loading branch information
pixlwave committed Aug 4, 2022
1 parent 9ab59b5 commit b771304
Show file tree
Hide file tree
Showing 8 changed files with 46 additions and 31 deletions.
4 changes: 2 additions & 2 deletions Riot/Modules/Application/LegacyAppDelegate.h
Original file line number Diff line number Diff line change
Expand Up @@ -234,10 +234,10 @@ UINavigationControllerDelegate
Process the fragment part of a vector.im link.
@param fragment the fragment part of the universal link.
@param universalLinkURL the unprocessed the universal link URL (optional).
@param universalLink the original universal link.
@return YES in case of processing success.
*/
- (BOOL)handleUniversalLinkFragment:(NSString*)fragment fromURL:(NSURL*)universalLinkURL;
- (BOOL)handleUniversalLinkFragment:(NSString*)fragment fromLink:(UniversalLink*)universalLink;

/**
Process the URL of a vector.im link.
Expand Down
26 changes: 9 additions & 17 deletions Riot/Modules/Application/LegacyAppDelegate.m
Original file line number Diff line number Diff line change
Expand Up @@ -1242,7 +1242,7 @@ - (BOOL)handleUniversalLink:(NSUserActivity*)userActivity
// Continue the registration with the passed nextLink
MXLogDebug(@"[AppDelegate] handleUniversalLink. Complete registration with nextLink");
NSURL *nextLink = [NSURL URLWithString:queryParams[@"nextLink"]];
[self handleUniversalLinkFragment:nextLink.fragment fromURL:nextLink];
[self handleUniversalLinkURL:nextLink];
}
else
{
Expand Down Expand Up @@ -1295,8 +1295,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);
Expand All @@ -1312,17 +1310,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;
Expand Down Expand Up @@ -1498,9 +1487,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];
}
Expand Down Expand Up @@ -1704,8 +1695,9 @@ - (BOOL)handleUniversalLinkURL:(NSURL*)universalLinkURL
{
// iOS Patch: fix vector.im urls before using it
NSURL *fixedURL = [Tools fixURLWithSeveralHashKeys:universalLinkURL];
UniversalLink *link = [[UniversalLink alloc] initWithUrl:universalLinkURL];

return [self handleUniversalLinkFragment:fixedURL.fragment fromURL:universalLinkURL];
return [self handleUniversalLinkFragment:fixedURL.fragment fromLink:link];
}

- (void)resetPendingUniversalLink
Expand Down
8 changes: 4 additions & 4 deletions Riot/Modules/Common/Recents/RecentsViewController.m
Original file line number Diff line number Diff line change
Expand Up @@ -1602,10 +1602,10 @@ - (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]];
[[AppDelegate theDelegate] handleUniversalLinkFragment:fragment fromURL:url];
// Create a permalink to open or preview the room.
NSString *permalink = [MXTools permalinkToRoom:roomIdOrAlias];
NSURL *permalinkURL = [NSURL URLWithString:permalink];
[[AppDelegate theDelegate] handleUniversalLinkURL:permalinkURL];
}
[tableView deselectRowAtIndexPath:indexPath animated:NO];
}
Expand Down
3 changes: 2 additions & 1 deletion Riot/Modules/Communities/Home/GroupHomeViewController.m
Original file line number Diff line number Diff line change
Expand Up @@ -892,7 +892,8 @@ - (BOOL)textView:(UITextView *)textView shouldInteractWithURL:(NSURL *)URL inRan
// Open the group or preview it
NSString *fragment = [NSString stringWithFormat:@"/group/%@",
[MXTools encodeURIComponent:absoluteURLString]];
[[AppDelegate theDelegate] handleUniversalLinkFragment:fragment fromURL:URL];
UniversalLink *link = [[UniversalLink alloc] initWithUrl:URL];
[[AppDelegate theDelegate] handleUniversalLinkFragment:fragment fromLink:link];
}

return shouldInteractWithURL;
Expand Down
7 changes: 4 additions & 3 deletions Riot/Modules/Room/RoomViewController.m
Original file line number Diff line number Diff line change
Expand Up @@ -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 handleUniversalLinkURL:permalinkURL];
}
// Preview the clicked group
else if ([MXTools isMatrixGroupIdentifier:absoluteURLString])
Expand Down
5 changes: 5 additions & 0 deletions Riot/Utils/UniversalLink.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
23 changes: 19 additions & 4 deletions Riot/Utils/UniversalLink.m
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand All @@ -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<NSString*> *pathParams;
NSMutableDictionary *queryParams = [NSMutableDictionary dictionary];

NSArray<NSString*> *fragments = [_url.fragment componentsSeparatedByString:@"?"];
NSArray<NSString*> *fragments = [url.fragment componentsSeparatedByString:@"?"];

// Extract path params
pathParams = [[fragments[0] stringByRemovingPercentEncoding] componentsSeparatedByString:@"/"];
Expand All @@ -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)
Expand Down
1 change: 1 addition & 0 deletions changelog.d/6492.bugfix
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Universal Links: Fix an infinite loop when handling a universal link for an unjoined room (or in some cases a crash).

0 comments on commit b771304

Please sign in to comment.