diff --git a/SoObjects/SOGo/NSString+Utilities.h b/SoObjects/SOGo/NSString+Utilities.h index 19a6d33c9..c531e1328 100644 --- a/SoObjects/SOGo/NSString+Utilities.h +++ b/SoObjects/SOGo/NSString+Utilities.h @@ -78,7 +78,8 @@ /* XSS protection */ - (NSString *) removeHTMLTagsExceptAnchorTags; -- (NSString *) stringWithoutHTMLInjection: (BOOL)stripHTMLCode; +- (NSString *) stringWithoutHTMLInjection: (BOOL)stripHTMLCode + stripAngular: (BOOL)stripAngular; #ifndef GNUSTEP_BASE_LIBRARY - (BOOL) boolValue; diff --git a/SoObjects/SOGo/NSString+Utilities.m b/SoObjects/SOGo/NSString+Utilities.m index 284d7e693..441d471eb 100644 --- a/SoObjects/SOGo/NSString+Utilities.m +++ b/SoObjects/SOGo/NSString+Utilities.m @@ -936,7 +936,7 @@ static int cssEscapingCount; * @param stripHTMLCode Remove all HTML code from content * @return A safe string */ -- (NSString *) stringWithoutHTMLInjection: (BOOL)stripHTMLCode +- (NSString *) stringWithoutHTMLInjection: (BOOL)stripHTMLCode stripAngular: (BOOL)stripAngular { NSString *result, *text, *newResult; NSScanner *theScanner; @@ -1058,17 +1058,21 @@ static int cssEscapingCount; // Remove @import css (in style tags) regex = [NSRegularExpression regularExpressionWithPattern:@"(<[\\s\\u200B \\\\0]*s[\\s\\u200B \\\\0]*t[\\s\\u200B \\\\0]*y[\\s\\u200B \\\\0]*l[\\s\\u200B \\\\0]*e.*)([\\s\\u200B \\\\0]*@[\\s\\u200B \\\\0]*i[\\s\\u200B \\\\0]*m[\\s\\u200B \\\\0]*p[\\s\\u200B \\\\0]*o[\\s\\u200B \\\\0]*r[\\s\\u200B \\\\0]*t)(.*<[\\s\\u200B \\\\0]*\\/[\\s\\u200B \\\\0]*s[\\s\\u200B \\\\0]*t[\\s\\u200B \\\\0]*y[\\s\\u200B \\\\0]*l[\\s\\u200B \\\\0]*e[\\s\\u200B \\\\0]*>)" options: NSRegularExpressionCaseInsensitive error:&error]; + newResult = [regex stringByReplacingMatchesInString:result options:0 range:NSMakeRange(0, [result length]) withTemplate:@"onrep***="]; + result = [NSString stringWithString: newResult]; - // Remove {{ and }} as they are interprated by angularJS with no way of escaping - regex = [NSRegularExpression regularExpressionWithPattern:@"(\\{\\{)|({{)" - options: NSRegularExpressionCaseInsensitive error:&error]; - newResult = [regex stringByReplacingMatchesInString:result options:0 range:NSMakeRange(0, [result length]) withTemplate:@"{\\\\{"]; - result = [NSString stringWithString: newResult]; - regex = [NSRegularExpression regularExpressionWithPattern:@"(\\}\\})|(}})" - options: NSRegularExpressionCaseInsensitive error:&error]; - newResult = [regex stringByReplacingMatchesInString:result options:0 range:NSMakeRange(0, [result length]) withTemplate:@"}/}"]; - result = [NSString stringWithString: newResult]; + if(stripAngular) { + // Remove {{ and }} as they are interprated by angularJS with no way of escaping + regex = [NSRegularExpression regularExpressionWithPattern:@"(\\{\\{)|({{)" + options: NSRegularExpressionCaseInsensitive error:&error]; + newResult = [regex stringByReplacingMatchesInString:result options:0 range:NSMakeRange(0, [result length]) withTemplate:@"{\\\\{"]; + result = [NSString stringWithString: newResult]; + regex = [NSRegularExpression regularExpressionWithPattern:@"(\\}\\})|(}})" + options: NSRegularExpressionCaseInsensitive error:&error]; + newResult = [regex stringByReplacingMatchesInString:result options:0 range:NSMakeRange(0, [result length]) withTemplate:@"}/}"]; + result = [NSString stringWithString: newResult]; + } newResult = result; while([regex numberOfMatchesInString:newResult options:0 range:NSMakeRange(0, [newResult length])] > 0) { diff --git a/SoObjects/SOGo/SOGoAdmin.m b/SoObjects/SOGo/SOGoAdmin.m index 18ced6727..287e01bd8 100644 --- a/SoObjects/SOGo/SOGoAdmin.m +++ b/SoObjects/SOGo/SOGoAdmin.m @@ -93,7 +93,7 @@ static const NSString *kCacheMotdKey = @"admin-motd"; NSException *error; NSString *safeMotd; - safeMotd = [motd stringWithoutHTMLInjection: NO]; + safeMotd = [motd stringWithoutHTMLInjection: NO stripAngular: NO]; error = [[[GCSFolderManager defaultFolderManager] adminFolder] writeMotd: safeMotd]; if (!error) { [[SOGoCache sharedCache] setValue:safeMotd forKey:kCacheMotdKey]; diff --git a/SoObjects/SOGo/SOGoUserDefaults.m b/SoObjects/SOGo/SOGoUserDefaults.m index 9ff37e9a4..13de03d55 100644 --- a/SoObjects/SOGo/SOGoUserDefaults.m +++ b/SoObjects/SOGo/SOGoUserDefaults.m @@ -152,7 +152,7 @@ NSString *SOGoPasswordRecoverySecondaryEmail = @"SecondaryEmail"; rc = NO; if ([fullName length]) - [identity setObject: [fullName stringWithoutHTMLInjection: YES] forKey: @"fullName"]; + [identity setObject: [fullName stringWithoutHTMLInjection: YES stripAngular:NO] forKey: @"fullName"]; if ([email length]) [identity setObject: email forKey: @"email"]; if ([replyTo length]) @@ -864,7 +864,7 @@ NSString *SOGoPasswordRecoverySecondaryEmail = @"SecondaryEmail"; if (mailIdentity && [mailIdentity objectForKey: @"fullName"]) { fullName = [NSString stringWithString: [mailIdentity objectForKey: @"fullName"]]; if (fullName) { - [mailIdentity setObject: [fullName stringWithoutHTMLInjection: YES] forKey: @"fullName"]; + [mailIdentity setObject: [fullName stringWithoutHTMLInjection: YES stripAngular:NO] forKey: @"fullName"]; [mailIdentities setObject: mailIdentity atIndexedSubscript: i]; } } diff --git a/UI/Common/UIxParentFolderActions.m b/UI/Common/UIxParentFolderActions.m index 5db60ccd6..b2e78a2a8 100644 --- a/UI/Common/UIxParentFolderActions.m +++ b/UI/Common/UIxParentFolderActions.m @@ -61,7 +61,7 @@ request = [context request]; params = [[request contentAsString] objectFromJSONString]; - name = [[params objectForKey: @"name"] stringWithoutHTMLInjection: YES]; + name = [[params objectForKey: @"name"] stringWithoutHTMLInjection: YES stripAngular:NO]; nameInContainer = nil; if ([name length] > 0) diff --git a/UI/Contacts/UIxContactEditor.m b/UI/Contacts/UIxContactEditor.m index a4d5f620b..5c7baf749 100644 --- a/UI/Contacts/UIxContactEditor.m +++ b/UI/Contacts/UIxContactEditor.m @@ -485,7 +485,7 @@ static Class SOGoContactGCSEntryK = Nil; co = [self clientObject]; card = [co vCard]; request = [context request]; - params = [[[request contentAsString] stringWithoutHTMLInjection: YES] objectFromJSONString]; + params = [[[request contentAsString] stringWithoutHTMLInjection: YES stripAngular:NO] objectFromJSONString]; forceSave = [[params objectForKey: @"ignoreDuplicate"] boolValue]; [self setAttributes: params]; diff --git a/UI/Contacts/UIxListEditor.m b/UI/Contacts/UIxListEditor.m index 477714c1d..e5d5c5a1f 100644 --- a/UI/Contacts/UIxListEditor.m +++ b/UI/Contacts/UIxListEditor.m @@ -339,7 +339,7 @@ [list retain]; request = [context request]; - params = [[[request contentAsString] stringWithoutHTMLInjection: YES] objectFromJSONString]; + params = [[[request contentAsString] stringWithoutHTMLInjection: YES stripAngular:NO] objectFromJSONString]; o = [params objectForKey: @"refs"]; if (![o isKindOfClass: [NSArray class]]) diff --git a/UI/MailPartViewers/UIxMailPartICalViewer.m b/UI/MailPartViewers/UIxMailPartICalViewer.m index d8f75272e..7775f950a 100644 --- a/UI/MailPartViewers/UIxMailPartICalViewer.m +++ b/UI/MailPartViewers/UIxMailPartICalViewer.m @@ -587,7 +587,7 @@ //Sanitise the html content if([d objectForKey:@"content"]){ - [d setObject: [[d objectForKey:@"content"] stringWithoutHTMLInjection: NO] forKey: @"content"]; + [d setObject: [[d objectForKey:@"content"] stringWithoutHTMLInjection: NO stripAngular:YES] forKey: @"content"]; } return d; diff --git a/UI/MailPartViewers/UIxMailPartViewer.m b/UI/MailPartViewers/UIxMailPartViewer.m index 7a2341c91..1e32db42e 100644 --- a/UI/MailPartViewers/UIxMailPartViewer.m +++ b/UI/MailPartViewers/UIxMailPartViewer.m @@ -201,7 +201,7 @@ - content = [[[self generateResponse] contentAsString] stringWithoutHTMLInjection: NO]; + content = [[[self generateResponse] contentAsString] stringWithoutHTMLInjection: NO stripAngular:YES]; if ([self respondsToSelector:@selector(getException)]) { e = [self getException]; } diff --git a/UI/MailerUI/UIxMailFolderActions.m b/UI/MailerUI/UIxMailFolderActions.m index 849e1e6d0..5d369bcd4 100644 --- a/UI/MailerUI/UIxMailFolderActions.m +++ b/UI/MailerUI/UIxMailFolderActions.m @@ -79,7 +79,7 @@ request = [context request]; params = [[request contentAsString] objectFromJSONString]; - folderName = [[params objectForKey: @"name"] stringWithoutHTMLInjection: YES]; + folderName = [[params objectForKey: @"name"] stringWithoutHTMLInjection: YES stripAngular:NO]; if ([folderName length] > 0) { encodedFolderName = [folderName stringByEncodingImap4FolderName]; @@ -145,7 +145,7 @@ // Retrieve new folder name from JSON payload request = [context request]; params = [[request contentAsString] objectFromJSONString]; - newFolderName = [[params objectForKey: @"name"] stringWithoutHTMLInjection: YES]; + newFolderName = [[params objectForKey: @"name"] stringWithoutHTMLInjection: YES stripAngular:NO]; if (!newFolderName || [newFolderName length] == 0) { diff --git a/UI/MailerUI/UIxMailListActions.m b/UI/MailerUI/UIxMailListActions.m index e019eb82f..71390f172 100644 --- a/UI/MailerUI/UIxMailListActions.m +++ b/UI/MailerUI/UIxMailListActions.m @@ -1178,7 +1178,7 @@ [msg addObject: [NSNumber numberWithBool: [self isMessageFlagged]]]; // Subject - [msg addObject: [[[self messageSubject] stringWithoutHTMLInjection: YES] stringWithoutHTMLInjection: NO]]; + [msg addObject: [[[self messageSubject] stringWithoutHTMLInjection: YES stripAngular:NO] stringWithoutHTMLInjection: NO stripAngular:NO]]; // From from = [[message objectForKey: @"envelope"] from]; diff --git a/UI/MailerUI/UIxMailView.m b/UI/MailerUI/UIxMailView.m index aee7cd563..99660edc9 100644 --- a/UI/MailerUI/UIxMailView.m +++ b/UI/MailerUI/UIxMailView.m @@ -363,7 +363,7 @@ static NSString *mailETag = nil; if ([self formattedDate]) [data setObject: [self formattedDate] forKey: @"date"]; if ([self messageSubject]) - [data setObject: [[[self messageSubject] stringWithoutHTMLInjection: YES] stringWithoutHTMLInjection: NO] forKey: @"subject"]; + [data setObject: [[[self messageSubject] stringWithoutHTMLInjection: YES stripAngular:YES] stringWithoutHTMLInjection: NO stripAngular:YES] forKey: @"subject"]; if ((addresses = [addressFormatter dictionariesForArray: [co fromEnvelopeAddresses]])) [data setObject: addresses forKey: @"from"]; if ((addresses = [addressFormatter dictionariesForArray: [co toEnvelopeAddresses]])) diff --git a/UI/MainUI/SOGoRootPage.m b/UI/MainUI/SOGoRootPage.m index 79130bc1e..7556723d6 100644 --- a/UI/MainUI/SOGoRootPage.m +++ b/UI/MainUI/SOGoRootPage.m @@ -1091,7 +1091,7 @@ static const NSString *kJwtKey = @"jwt"; } //Check common injection - loginClean = [login stringWithoutHTMLInjection: YES]; + loginClean = [login stringWithoutHTMLInjection: YES stripAngular:NO]; if(![loginClean isEqualToString: login]) { loginClean = @""; diff --git a/UI/PreferencesUI/UIxPreferences.m b/UI/PreferencesUI/UIxPreferences.m index c8fae8007..d6a4b5b5f 100644 --- a/UI/PreferencesUI/UIxPreferences.m +++ b/UI/PreferencesUI/UIxPreferences.m @@ -1750,7 +1750,7 @@ static NSArray *reminderValues = nil; id o, v; requestStr = [[context request] contentAsString]; - requestStr = [requestStr stringWithoutHTMLInjection: NO]; + requestStr = [requestStr stringWithoutHTMLInjection: NO stripAngular:NO]; o = [requestStr objectFromJSONString]; results = nil; diff --git a/UI/SOGoUI/UIxComponent.m b/UI/SOGoUI/UIxComponent.m index 012d6edea..5cd0c27fc 100644 --- a/UI/SOGoUI/UIxComponent.m +++ b/UI/SOGoUI/UIxComponent.m @@ -403,7 +403,7 @@ static SoProduct *commonProduct = nil; theme = [[context request] formValueForKey: @"theme"]; if ([theme length]) { - safeTheme = [theme stringWithoutHTMLInjection: YES]; + safeTheme = [theme stringWithoutHTMLInjection: YES stripAngular:NO]; if([safeTheme isEqualToString: theme]) rel = [NSString stringWithFormat: @"%@?theme=%@", rel, theme]; } diff --git a/UI/Scheduler/UIxAppointmentEditor.m b/UI/Scheduler/UIxAppointmentEditor.m index 27b94ef17..1c3621607 100644 --- a/UI/Scheduler/UIxAppointmentEditor.m +++ b/UI/Scheduler/UIxAppointmentEditor.m @@ -556,7 +556,7 @@ ex = nil; request = [context request]; - params = [[[request contentAsString] stringWithoutHTMLInjection: NO] objectFromJSONString]; + params = [[[request contentAsString] stringWithoutHTMLInjection: NO stripAngular:NO] objectFromJSONString]; if (params == nil) { ex = [NSException exceptionWithName: @"JSONParsingException" diff --git a/UI/Scheduler/UIxCalendarSelector.m b/UI/Scheduler/UIxCalendarSelector.m index 76c69d126..db0deb7ac 100644 --- a/UI/Scheduler/UIxCalendarSelector.m +++ b/UI/Scheduler/UIxCalendarSelector.m @@ -182,7 +182,7 @@ _intValueFromHex (NSString *hexString) fActiveTasks = [folder activeTasks]; [calendar setObject: folderName forKey: @"id"]; - [calendar setObject: [fDisplayName stringWithoutHTMLInjection: YES] forKey: @"name"]; + [calendar setObject: [fDisplayName stringWithoutHTMLInjection: YES stripAngular:NO] forKey: @"name"]; [calendar setObject: [folder calendarColor] forKey: @"color"]; isActive = [NSNumber numberWithBool: [folder isActive]]; [calendar setObject: isActive forKey: @"active"]; diff --git a/UI/Scheduler/UIxTaskEditor.m b/UI/Scheduler/UIxTaskEditor.m index 8f2e136a8..e1c7a9b92 100644 --- a/UI/Scheduler/UIxTaskEditor.m +++ b/UI/Scheduler/UIxTaskEditor.m @@ -335,7 +335,7 @@ ex = nil; request = [context request]; - params = [[[request contentAsString] stringWithoutHTMLInjection: NO] objectFromJSONString]; + params = [[[request contentAsString] stringWithoutHTMLInjection: NO stripAngular:NO] objectFromJSONString]; if (params == nil) { ex = [NSException exceptionWithName: @"JSONParsingException"