Skip to content

Commit

Permalink
6.4.5 (#1257)
Browse files Browse the repository at this point in the history
- Make discovery of group/channel names more reliable
- Try to make crashes in link preview less likely
- Don't crash on errors when adding a new account
- Don't leave messages in "Sending..." state after resuming the app from
background
- Allow adding gateway jids as contacts
- Make group/channel detection more reliable when adding via jid
  • Loading branch information
tmolitor-stud-tu authored Oct 12, 2024
2 parents 7a7ea32 + 61d4698 commit f95b8b3
Show file tree
Hide file tree
Showing 7 changed files with 59 additions and 37 deletions.
9 changes: 0 additions & 9 deletions Monal/Classes/AccountListController.m
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,6 @@ -(void) refreshAccountList
-(void) initContactCell:(MLSwitchCell*) cell forAccNo:(NSUInteger) accNo
{
[cell initTapCell:@"\n\n"];
cell = [cell initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:@"AccountCell"];
NSDictionary* account = [self.accountList objectAtIndex:accNo];
MLAssert(account != nil, ([NSString stringWithFormat:@"Expected non nil account in row %lu", (unsigned long)accNo]));
if([(NSString*)[account objectForKey:@"domain"] length] > 0) {
Expand All @@ -89,7 +88,6 @@ -(void) initContactCell:(MLSwitchCell*) cell forAccNo:(NSUInteger) accNo
}

UIImageView* accessory = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, 30, 30)];
cell.detailTextLabel.text = nil;

if([[account objectForKey:@"enabled"] boolValue] == YES)
{
Expand All @@ -98,25 +96,18 @@ -(void) initContactCell:(MLSwitchCell*) cell forAccNo:(NSUInteger) accNo
{
accessory.image = [UIImage imageNamed:@"Connected"];
cell.accessoryView = accessory;

NSDate* connectedTime = [[MLXMPPManager sharedInstance] connectedTimeFor:[[self.accountList objectAtIndex:accNo] objectForKey:@"account_id"]];
if(connectedTime) {
cell.detailTextLabel.text = [NSString stringWithFormat:NSLocalizedString(@"Connected since: %@", @""), [self.uptimeFormatter stringFromDate:connectedTime]];
}
}
else
{
accessory.image = [UIImage imageNamed:@"Disconnected"];
cell.accessoryView = accessory;
cell.detailTextLabel.text = NSLocalizedString(@"Connecting...", @"");
}
}
else
{
cell.imageView.image = [UIImage systemImageNamed:@"circle"];
accessory.image = nil;
cell.accessoryView = accessory;
cell.detailTextLabel.text = NSLocalizedString(@"Account disabled", @"");
}
}

Expand Down
13 changes: 12 additions & 1 deletion Monal/Classes/MLDelayableTimer.m
Original file line number Diff line number Diff line change
Expand Up @@ -77,9 +77,15 @@ -(void) pause
DDLogWarn(@"Tried to pause already fired timer: %@", self);
return;
}
NSTimeInterval remaining = _wrappedTimer.fireDate.timeIntervalSinceNow;
if(remaining == 0)
{
DDLogWarn(@"Tried to pause timer the exact second its firing: %@", self);
return;
}
DDLogDebug(@"Pausing timer: %@", self);
_remainingTime = _wrappedTimer.fireDate.timeIntervalSinceNow;
_wrappedTimer.fireDate = NSDate.distantFuture; //postpone timer virtually indefinitely
_remainingTime = remaining;
}
}

Expand All @@ -91,6 +97,11 @@ -(void) resume
DDLogWarn(@"Tried to resume already fired timer: %@", self);
return;
}
if(_remainingTime == 0)
{
DDLogWarn(@"Tried to resume non-paused timer: %@", self);
return;
}
DDLogDebug(@"Resuming timer: %@", self);
_wrappedTimer.fireDate = [NSDate dateWithTimeIntervalSinceNow:_remainingTime];
_remainingTime = 0;
Expand Down
2 changes: 1 addition & 1 deletion Monal/Classes/MLMucProcessor.m
Original file line number Diff line number Diff line change
Expand Up @@ -1417,7 +1417,7 @@ -(void) publishAvatar:(UIImage* _Nullable) image forMuc:(NSString*) room
}

//extract further muc infos
NSString* mucName = [iqNode findFirst:@"{http://jabber.org/protocol/disco#info}query/\\{http://jabber.org/protocol/muc#roominfo}result@muc#roomconfig_roomname\\"];
NSString* mucName = [iqNode findFirst:@"{http://jabber.org/protocol/disco#info}query/identity@name"];
NSString* mucType = @"channel";
//both are needed for omemo, see discussion with holger 2021-01-02/03 -- Thilo Molitor
//see also: https://docs.modernxmpp.org/client/groupchat/
Expand Down
43 changes: 24 additions & 19 deletions Monal/Classes/MLStream.m
Original file line number Diff line number Diff line change
Expand Up @@ -687,25 +687,30 @@ -(void) generateEvent:(NSStreamEvent) event
//don't schedule delegate calls if no runloop was specified
if(self.shared_state.runLoop == nil)
return;
//schedule the delegate calls in the runloop that was registered
CFRunLoopPerformBlock([self.shared_state.runLoop getCFRunLoop], (__bridge CFStringRef)self.shared_state.runLoopMode, ^{
@synchronized(self.shared_state) {
if(event == NSStreamEventOpenCompleted && self.open_called && self.shared_state.open)
[self->_delegate stream:self handleEvent:event];
else if(event == NSStreamEventHasBytesAvailable && self.open_called && self.shared_state.open)
[self->_delegate stream:self handleEvent:event];
else if(event == NSStreamEventHasSpaceAvailable && self.open_called && self.shared_state.open)
[self->_delegate stream:self handleEvent:event];
else if(event == NSStreamEventErrorOccurred)
[self->_delegate stream:self handleEvent:event];
else if(event == NSStreamEventEndEncountered && self.open_called && self.shared_state.open)
[self->_delegate stream:self handleEvent:event];
else
DDLogVerbose(@"Ignored event %ld", (long)event);
}
});
//trigger wakeup of runloop to execute the block as soon as possible
CFRunLoopWakeUp([self.shared_state.runLoop getCFRunLoop]);
//make sure to NOT hold the @synchronized lock when calling the delegate to not introduce deadlocks
BOOL handleEvent = NO;
if(event == NSStreamEventOpenCompleted && self.open_called && self.shared_state.open)
handleEvent = YES;
else if(event == NSStreamEventHasBytesAvailable && self.open_called && self.shared_state.open)
handleEvent = YES;
else if(event == NSStreamEventHasSpaceAvailable && self.open_called && self.shared_state.open)
handleEvent = YES;
else if(event == NSStreamEventErrorOccurred)
handleEvent = YES;
else if(event == NSStreamEventEndEncountered && self.open_called && self.shared_state.open)
handleEvent = YES;
//check if the event should be handled
if(!handleEvent)
DDLogVerbose(@"Ignoring event %ld", (long)event);
else
{
//schedule the delegate calls in the runloop that was registered
CFRunLoopPerformBlock([self.shared_state.runLoop getCFRunLoop], (__bridge CFStringRef)self.shared_state.runLoopMode, ^{
[self->_delegate stream:self handleEvent:event];
});
//trigger wakeup of runloop to execute the block as soon as possible
CFRunLoopWakeUp([self.shared_state.runLoop getCFRunLoop]);
}
}
}

Expand Down
4 changes: 4 additions & 0 deletions Monal/Classes/MonalAppDelegate.m
Original file line number Diff line number Diff line change
Expand Up @@ -1269,6 +1269,10 @@ -(void) showConnectionStatus:(NSNotification*) notification
{
dispatch_async(dispatch_get_main_queue(), ^{
xmpp* xmppAccount = notification.object;
//ignore errors with unknown accounts
//(possibly meaning an account we currently try to create --> the creating ui will take care of this already)
if(xmppAccount == nil)
return;
if(![notification.userInfo[@"isSevere"] boolValue])
DDLogError(@"Minor XMPP Error(%@): %@", xmppAccount.connectionProperties.identity.jid, notification.userInfo[@"message"]);
NotificationBanner* banner = [[NotificationBanner alloc] initWithTitle:xmppAccount.connectionProperties.identity.jid subtitle:notification.userInfo[@"message"] leftView:nil rightView:nil style:([notification.userInfo[@"isSevere"] boolValue] ? BannerStyleDanger : BannerStyleWarning) colors:nil];
Expand Down
12 changes: 8 additions & 4 deletions Monal/Classes/chatViewController.m
Original file line number Diff line number Diff line change
Expand Up @@ -3010,7 +3010,7 @@ -(void) loadPreviewWithUrlForRow:(NSIndexPath *) indexPath withResultHandler:(mo
return;
}
//limit to 512KB of html
if(contentLength.intValue > 524288)
if(contentLength.intValue > 65536)
{
DDLogWarn(@"Now loading preview HTML for %@ with byte range 0-512k...", row.url);
[self downloadPreviewWithRow:indexPath usingByterange:YES andResultHandler:resultHandler];
Expand Down Expand Up @@ -3051,7 +3051,7 @@ -(void) downloadPreviewWithRow:(NSIndexPath*) indexPath usingByterange:(BOOL) us
request.requiresDNSSECValidation = YES;
[request setValue:@"facebookexternalhit/1.1" forHTTPHeaderField:@"User-Agent"]; //required on some sites for og tags e.g. youtube
if(useByterange)
[request setValue:@"bytes=0-524288" forHTTPHeaderField:@"Range"];
[request setValue:@"bytes=0-65536" forHTTPHeaderField:@"Range"];
request.timeoutInterval = 10;
NSURLSession* session = [HelperTools createEphemeralURLSession];
[[session dataTaskWithRequest:request completionHandler:^(NSData* _Nullable data, NSURLResponse* _Nullable response, NSError* _Nullable error) {
Expand All @@ -3060,10 +3060,14 @@ -(void) downloadPreviewWithRow:(NSIndexPath*) indexPath usingByterange:(BOOL) us
else
{
NSString* body = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
NSURL* baseURL = [NSURL URLWithString:[NSString stringWithFormat:@"%@://%@%@", row.url.scheme, row.url.host, row.url.path]];
MLOgHtmlParser* ogParser = [[MLOgHtmlParser alloc] initWithHtml:body andBaseUrl:baseURL];
MLOgHtmlParser* ogParser = nil;
NSString* text = nil;
NSURL* image = nil;
if([body length] <= 65536)
{
NSURL* baseURL = [NSURL URLWithString:[NSString stringWithFormat:@"%@://%@%@", row.url.scheme, row.url.host, row.url.path]];
ogParser = [[MLOgHtmlParser alloc] initWithHtml:body andBaseUrl:baseURL];
}
if(ogParser != nil)
{
text = [ogParser getOgTitle];
Expand Down
13 changes: 10 additions & 3 deletions Monal/Classes/xmpp.m
Original file line number Diff line number Diff line change
Expand Up @@ -2955,7 +2955,7 @@ -(void) handleFeaturesBeforeAuth:(MLXMLNode*) parsedStanza withForceSasl2:(BOOL)
//leave that in for translators, we might use it at a later time
while(!NSLocalizedString(@"This server isn't additionally hardened against man-in-the-middle attacks on the TLS encryption layer by using authentication methods that are secure against such attacks! This indicates an ongoing attack if the server is supposed to support SASL2 and SCRAM and is harmless otherwise. Use the advanced account creation menu and turn on the PLAIN switch there if you still want to log in to this server.", @""));

clearPipelineCacheOrReportSevereError(NSLocalizedString(@"This server lacks support for SASL2 and SCRAM, additionally hardening authentication against man-in-the-middle attacks on the TLS encryption layer. Since this server is listed as supporting both at https://github.com/monal-im/SCRAM_PreloadList, an ongoing MITM attack is highly likely! You should try again once you are in a clean networking environment.", @""));
clearPipelineCacheOrReportSevereError(NSLocalizedString(@"This server lacks support for SASL2 and SCRAM, additionally hardening authentication against man-in-the-middle attacks on the TLS encryption layer. Since this server is listed as supporting both at https://github.com/monal-im/SCRAM_PreloadList (or you intentionally left the PLAIN switch off when using the advanced account creation menu), an ongoing MITM attack is very likely! Try again once you are in a clean network environment.", @""));
return;
}
}
Expand Down Expand Up @@ -4471,9 +4471,16 @@ -(AnyPromise*) checkJidType:(NSString*) jid
[discoInfo setiqTo:jid];
[discoInfo setDiscoInfoNode];
[self sendIq:discoInfo withResponseHandler:^(XMPPIQ* response) {
NSSet* identities = [NSSet setWithArray:[response find:@"{http://jabber.org/protocol/disco#info}query/identity@category"]];
NSSet* features = [NSSet setWithArray:[response find:@"{http://jabber.org/protocol/disco#info}query/feature@var"]];
//check if this is a muc or account
if([features containsObject:@"http://jabber.org/protocol/muc"])
//check if this is an account or a muc
//this test has to come first because a gateway component may have an "account" identity while also supporintg MUC.
//usually this means that there's a bot at the component's address that facilitates registration without adhoc commands.
//the "account" jidType makes it possible to add the component as a contact.
if([identities containsObject:@"account"])
return resolve(@"account");
else if([identities containsObject:@"conference"]
&& [features containsObject:@"http://jabber.org/protocol/muc"])
return resolve(@"muc");
else
return resolve(@"account");
Expand Down

0 comments on commit f95b8b3

Please sign in to comment.