Skip to content

Commit

Permalink
Fix xmpp: uri handling (qrcode or from other apps)
Browse files Browse the repository at this point in the history
  • Loading branch information
tmolitor-stud-tu committed Aug 17, 2024
1 parent 4e55d7f commit 61bc554
Show file tree
Hide file tree
Showing 3 changed files with 116 additions and 102 deletions.
2 changes: 2 additions & 0 deletions Monal/Classes/ActiveChatsViewController.h
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,8 @@ NS_ASSUME_NONNULL_BEGIN
-(void) showAddContact;
-(void) sheetDismissed;

-(void) segueToIntroScreensIfNeeded;
-(void) resetViewQueue;
-(void) dismissCompleteViewChainWithAnimation:(BOOL) animation andCompletion:(monal_void_block_t _Nullable) completion;

@end
Expand Down
5 changes: 5 additions & 0 deletions Monal/Classes/ActiveChatsViewController.m
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,11 @@ -(void) commonInit
_blockQueueSemaphore = dispatch_semaphore_create(1);
}

-(void) resetViewQueue
{
[_blockQueue removeAllObjects];
}

-(void) prependToViewQueue:(view_queue_block_t) block withId:(MLViewID) viewId andFile:(char*) file andLine:(int) line andFunc:(char*) func
{
@synchronized(_blockQueue) {
Expand Down
211 changes: 109 additions & 102 deletions Monal/Classes/MonalAppDelegate.m
Original file line number Diff line number Diff line change
Expand Up @@ -711,120 +711,127 @@ -(void) handleXMPPURL:(NSURL*) url
while(self.activeChats == nil)
usleep(100000);
dispatch_async(dispatch_get_main_queue(), ^{
BOOL registerNeeded = [MLXMPPManager sharedInstance].connectedXMPP.count == 0;
NSURLComponents* components = [NSURLComponents componentsWithURL:url resolvingAgainstBaseURL:NO];
DDLogVerbose(@"URI path '%@'", components.path);
DDLogVerbose(@"URI query '%@'", components.query);

NSString* jid = components.path;
NSDictionary* jidParts = [HelperTools splitJid:jid];
BOOL isRegister = NO;
BOOL isRoster = NO;
BOOL isGroupJoin = NO;
BOOL isIbr = NO;
NSString* preauthToken = nil;
NSMutableDictionary<NSNumber*, NSData*>* omemoFingerprints = [NSMutableDictionary new];
//someone had the really superior (NOT!) idea to split uri query parts by ';' instead of the standard '&'
//making all existing uri libs useless, see: https://xmpp.org/extensions/xep-0147.html
//blame this author: Peter Saint-Andre
NSArray* queryItems = [components.query componentsSeparatedByString:@";"];
for(NSString* item in queryItems)
{
NSArray* itemParts = [item componentsSeparatedByString:@"="];
NSString* name = itemParts[0];
NSString* value = @"";
if([itemParts count] > 1)
value = itemParts[1];
DDLogVerbose(@"URI part '%@' = '%@'", name, value);
if([name isEqualToString:@"register"])
isRegister = YES;
if([name isEqualToString:@"roster"])
isRoster = YES;
if([name isEqualToString:@"join"])
isGroupJoin = YES;
if([name isEqualToString:@"ibr"] && [value isEqualToString:@"y"])
isIbr = YES;
if([name isEqualToString:@"preauth"])
preauthToken = [value copy];
if([name hasPrefix:@"omemo-sid-"])
//remove everything from our view queue (including currently displayed views)
//and add intro screens back to the queue, if needed, followed by the view handling the xmpp uri action
[self.activeChats resetViewQueue];
[self.activeChats dismissCompleteViewChainWithAnimation:NO andCompletion:^{
[self.activeChats segueToIntroScreensIfNeeded];

BOOL registerNeeded = [MLXMPPManager sharedInstance].connectedXMPP.count == 0;
NSURLComponents* components = [NSURLComponents componentsWithURL:url resolvingAgainstBaseURL:NO];
DDLogVerbose(@"URI path '%@'", components.path);
DDLogVerbose(@"URI query '%@'", components.query);

NSString* jid = components.path;
NSDictionary* jidParts = [HelperTools splitJid:jid];
BOOL isRegister = NO;
BOOL isRoster = NO;
BOOL isGroupJoin = NO;
BOOL isIbr = NO;
NSString* preauthToken = nil;
NSMutableDictionary<NSNumber*, NSData*>* omemoFingerprints = [NSMutableDictionary new];
//someone had the really superior (NOT!) idea to split uri query parts by ';' instead of the standard '&'
//making all existing uri libs useless, see: https://xmpp.org/extensions/xep-0147.html
//blame this author: Peter Saint-Andre
NSArray* queryItems = [components.query componentsSeparatedByString:@";"];
for(NSString* item in queryItems)
{
NSNumber* sid = [NSNumber numberWithUnsignedInteger:(NSUInteger)[[name substringFromIndex:10] longLongValue]];
NSData* fingerprint = [HelperTools signalIdentityWithHexKey:value];
omemoFingerprints[sid] = fingerprint;
NSArray* itemParts = [item componentsSeparatedByString:@"="];
NSString* name = itemParts[0];
NSString* value = @"";
if([itemParts count] > 1)
value = itemParts[1];
DDLogVerbose(@"URI part '%@' = '%@'", name, value);
if([name isEqualToString:@"register"])
isRegister = YES;
if([name isEqualToString:@"roster"])
isRoster = YES;
if([name isEqualToString:@"join"])
isGroupJoin = YES;
if([name isEqualToString:@"ibr"] && [value isEqualToString:@"y"])
isIbr = YES;
if([name isEqualToString:@"preauth"])
preauthToken = [value copy];
if([name hasPrefix:@"omemo-sid-"])
{
NSNumber* sid = [NSNumber numberWithUnsignedInteger:(NSUInteger)[[name substringFromIndex:10] longLongValue]];
NSData* fingerprint = [HelperTools signalIdentityWithHexKey:value];
omemoFingerprints[sid] = fingerprint;
}
}
}

if(!jidParts[@"host"])
{
DDLogError(@"Ignoring xmpp: uri without host jid part!");
return;
}

#ifdef IS_QUICKSY
//make sure we hit the else below, even if (isRegister || (isRoster && registerNeeded)) == YES
if(NO)
;
#else
if(isRegister || (isRoster && registerNeeded))
{
NSString* username = nilDefault(jidParts[@"node"], @"");
NSString* host = jidParts[@"host"];

if(isRoster)
if(!jidParts[@"host"])
{
//isRoster variant does not specify a predefined username for the new account, register does (but this is still optional)
username = @"";
//isRoster variant without ibr does not specify a host to register on, too
if(!isIbr)
host = @"";
DDLogError(@"Ignoring xmpp: uri without host jid part!");
return;
}

//show register view and, if isRoster, add contact as usual after register (e.g. call this method again)
weakify(self);
[self.activeChats showRegisterWithUsername:username onHost:host withToken:preauthToken usingCompletion:^(NSNumber* accountNo) {
strongify(self);
DDLogVerbose(@"Got accountNo for newly registered account: %@", accountNo);
xmpp* account = [[MLXMPPManager sharedInstance] getConnectedAccountForID:accountNo];
DDLogInfo(@"Got newly registered account: %@", account);
#ifdef IS_QUICKSY
//make sure we hit the else below, even if (isRegister || (isRoster && registerNeeded)) == YES
if(NO)
;
#else
if(isRegister || (isRoster && registerNeeded))
{
NSString* username = nilDefault(jidParts[@"node"], @"");
NSString* host = jidParts[@"host"];

//this should never happen
MLAssert(account != nil, @"Can not use account after register!", (@{
@"components": components,
@"username": username,
@"host": host,
}));
if(isRoster)
{
//isRoster variant does not specify a predefined username for the new account, register does (but this is still optional)
username = @"";
//isRoster variant without ibr does not specify a host to register on, too
if(!isIbr)
host = @"";
}

//add given jid to our roster if in roster mode (e.g. the jid is not the jid we just registered as like in register mode)
if(account != nil && isRoster) //silence memory warning despite assertion above
return [self handleXMPPURL:url];
}];
}
//show register view and, if isRoster, add contact as usual after register (e.g. call this method again)
weakify(self);
[self.activeChats showRegisterWithUsername:username onHost:host withToken:preauthToken usingCompletion:^(NSNumber* accountNo) {
strongify(self);
DDLogVerbose(@"Got accountNo for newly registered account: %@", accountNo);
xmpp* account = [[MLXMPPManager sharedInstance] getConnectedAccountForID:accountNo];
DDLogInfo(@"Got newly registered account: %@", account);

//this should never happen
MLAssert(account != nil, @"Can not use account after register!", (@{
@"components": components,
@"username": username,
@"host": host,
}));

//add given jid to our roster if in roster mode (e.g. the jid is not the jid we just registered as like in register mode)
if(account != nil && isRoster) //silence memory warning despite assertion above
return [self handleXMPPURL:url];
}];
}
#endif
//I know this if is moot, but I wanted to preserve the different cases:
//either we already have one or more accounts and the xmpp: uri is of type subscription (ibr does not matter here,
//because we already have an account) or muc join
//OR the xmpp: uri is a normal xmpp uri having only a jid we should add as our new contact (preauthToken will be nil in this case)
else if((!registerNeeded && (isRoster || isGroupJoin)) || !registerNeeded)
{
if([MLXMPPManager sharedInstance].connectedXMPP.count == 1)
//I know this if is moot, but I wanted to preserve the different cases:
//either we already have one or more accounts and the xmpp: uri is of type subscription (ibr does not matter here,
//because we already have an account) or muc join
//OR the xmpp: uri is a normal xmpp uri having only a jid we should add as our new contact (preauthToken will be nil in this case)
else if((!registerNeeded && (isRoster || isGroupJoin)) || !registerNeeded)
{
//the add contacts ui will check if the contact is already present on the selected account
xmpp* account = [[MLXMPPManager sharedInstance].connectedXMPP firstObject];
[self.activeChats showAddContactWithJid:jid preauthToken:preauthToken prefillAccount:account andOmemoFingerprints:omemoFingerprints];
if([MLXMPPManager sharedInstance].connectedXMPP.count == 1)
{
//the add contacts ui will check if the contact is already present on the selected account
xmpp* account = [[MLXMPPManager sharedInstance].connectedXMPP firstObject];
[self.activeChats showAddContactWithJid:jid preauthToken:preauthToken prefillAccount:account andOmemoFingerprints:omemoFingerprints];
}
else
//the add contacts ui will check if the contact is already present on the selected account
[self.activeChats showAddContactWithJid:jid preauthToken:preauthToken prefillAccount:nil andOmemoFingerprints:omemoFingerprints];
}
else
//the add contacts ui will check if the contact is already present on the selected account
[self.activeChats showAddContactWithJid:jid preauthToken:preauthToken prefillAccount:nil andOmemoFingerprints:omemoFingerprints];
}
else
{
DDLogError(@"No account available to handel xmpp: uri!");

UIAlertController* messageAlert = [UIAlertController alertControllerWithTitle:NSLocalizedString(@"Error adding contact or channel", @"") message:NSLocalizedString(@"No account available to handel 'xmpp:' URI!", @"") preferredStyle:UIAlertControllerStyleAlert];
[messageAlert addAction:[UIAlertAction actionWithTitle:NSLocalizedString(@"Close", @"") style:UIAlertActionStyleCancel handler:^(UIAlertAction* action __unused) {
}]];
[self.activeChats presentViewController:messageAlert animated:YES completion:nil];
}
{
DDLogError(@"No account available to handel xmpp: uri!");

UIAlertController* messageAlert = [UIAlertController alertControllerWithTitle:NSLocalizedString(@"Error adding contact or channel", @"") message:NSLocalizedString(@"No account available to handel 'xmpp:' URI!", @"") preferredStyle:UIAlertControllerStyleAlert];
[messageAlert addAction:[UIAlertAction actionWithTitle:NSLocalizedString(@"Close", @"") style:UIAlertActionStyleCancel handler:^(UIAlertAction* action __unused) {
}]];
[self.activeChats presentViewController:messageAlert animated:YES completion:nil];
}
}];
});
});
}
Expand Down

0 comments on commit 61bc554

Please sign in to comment.