Merge branch 'hotfix/2.19.7'
This commit is contained in:
commit
d648a258d1
2
Pods
2
Pods
@ -1 +1 @@
|
||||
Subproject commit a8334500da7c8180341043d84b0b41145e6619e1
|
||||
Subproject commit dab63d5412cf0d8777bd11259c86a56b1ec25bab
|
||||
1505
Signal/src/Profiles/OWSProfileManager.m
Normal file
1505
Signal/src/Profiles/OWSProfileManager.m
Normal file
File diff suppressed because it is too large
Load Diff
@ -13,6 +13,7 @@
|
||||
#import "FingerprintViewController.h"
|
||||
#import "HomeViewController.h"
|
||||
#import "MediaDetailViewController.h"
|
||||
#import "NSString+OWS.h"
|
||||
#import "NotificationsManager.h"
|
||||
#import "OWSAnyTouchGestureRecognizer.h"
|
||||
#import "OWSAudioAttachmentPlayer.h"
|
||||
@ -67,6 +68,7 @@
|
||||
#import <SignalServiceKit/NSData+Image.h>
|
||||
#import <SignalServiceKit/NSDate+OWS.h>
|
||||
#import <SignalServiceKit/NSNotificationCenter+OWS.h>
|
||||
#import <SignalServiceKit/NSString+SSK.h>
|
||||
#import <SignalServiceKit/NSTimer+OWS.h>
|
||||
#import <SignalServiceKit/OWSAcknowledgeMessageDeliveryRequest.h>
|
||||
#import <SignalServiceKit/OWSAnalytics.h>
|
||||
|
||||
@ -277,6 +277,14 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
actionBlock:^{
|
||||
[DebugUIMessages injectFakeIncomingMessages:1000 thread:thread];
|
||||
}],
|
||||
[OWSTableItem itemWithTitle:@"Test Indic Scripts"
|
||||
actionBlock:^{
|
||||
[DebugUIMessages testIndicScriptsInThread:thread];
|
||||
}],
|
||||
[OWSTableItem itemWithTitle:@"Test Zalgo"
|
||||
actionBlock:^{
|
||||
[DebugUIMessages testZalgoTextInThread:thread];
|
||||
}],
|
||||
] mutableCopy];
|
||||
if ([thread isKindOfClass:[TSContactThread class]]) {
|
||||
TSContactThread *contactThread = (TSContactThread *)thread;
|
||||
@ -1593,6 +1601,90 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
}];
|
||||
}
|
||||
|
||||
+ (void)testIndicScriptsInThread:(TSThread *)thread
|
||||
{
|
||||
NSArray<NSString *> *strings = @[
|
||||
@"\u0C1C\u0C4D\u0C1E\u200C\u0C3E",
|
||||
@"\u09B8\u09CD\u09B0\u200C\u09C1",
|
||||
@"non-crashing string",
|
||||
];
|
||||
|
||||
[TSStorageManager.sharedManager.dbReadWriteConnection
|
||||
readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
|
||||
for (NSString *string in strings) {
|
||||
// DO NOT log these strings with the debugger attached.
|
||||
// DDLogInfo(@"%@ %@", self.logTag, string);
|
||||
|
||||
{
|
||||
TSIncomingMessage *message =
|
||||
[[TSIncomingMessage alloc] initWithTimestamp:[NSDate ows_millisecondTimeStamp]
|
||||
inThread:thread
|
||||
authorId:@"+19174054215"
|
||||
sourceDeviceId:0
|
||||
messageBody:string];
|
||||
[message saveWithTransaction:transaction];
|
||||
[message markAsReadWithTransaction:transaction sendReadReceipt:NO updateExpiration:NO];
|
||||
}
|
||||
{
|
||||
NSString *recipientId = @"+19174054215";
|
||||
NSString *groupName = string;
|
||||
NSMutableArray<NSString *> *recipientIds = [@[
|
||||
recipientId,
|
||||
[TSAccountManager localNumber],
|
||||
] mutableCopy];
|
||||
NSData *groupId = [SecurityUtils generateRandomBytes:16];
|
||||
TSGroupModel *groupModel =
|
||||
[[TSGroupModel alloc] initWithTitle:groupName memberIds:recipientIds image:nil groupId:groupId];
|
||||
|
||||
TSGroupThread *groupThread =
|
||||
[TSGroupThread getOrCreateThreadWithGroupModel:groupModel transaction:transaction];
|
||||
OWSAssert(groupThread);
|
||||
}
|
||||
}
|
||||
}];
|
||||
}
|
||||
|
||||
+ (void)testZalgoTextInThread:(TSThread *)thread
|
||||
{
|
||||
NSArray<NSString *> *strings = @[
|
||||
@"Ṱ̴̤̺̣͚͚̭̰̤̮̑̓̀͂͘͡h̵̢̤͔̼̗̦̖̬͌̀͒̀͘i̴̮̤͎͎̝̖̻͓̅̆͆̓̎͘͡ͅŝ̡̡̳͔̓͗̾̀̇͒͘͢͢͡͡ ỉ̛̲̩̫̝͉̀̒͐͋̾͘͢͡͞s̶̨̫̞̜̹͛́̇͑̅̒̊̈ s̵͍̲̗̠̗͈̦̬̉̿͂̏̐͆̾͐͊̾ǫ̶͍̼̝̉͊̉͢͜͞͝ͅͅṁ̵̡̨̬̤̝͔̣̄̍̋͊̿̄͋̈ͅe̪̪̻̱͖͚͈̲̍̃͘͠͝ z̷̢̢̛̩̦̱̺̼͑́̉̾ą͕͎̠̮̹̱̓̔̓̈̈́̅̐͢l̵̨͚̜͉̟̜͉͎̃͆͆͒͑̍̈̚͜͞ğ͔̖̫̞͎͍̒̂́̒̿̽̆͟o̶̢̬͚̘̤̪͇̻̒̋̇̊̏͢͡͡͠ͅ t̡̛̥̦̪̮̅̓̑̈́̉̓̽͛͢͡ȩ̡̩͓͈̩͎͗̔͑̌̓͊͆͝x̫̦͓̤͓̘̝̪͊̆͌͊̽̃̏͒͘͘͢ẗ̶̢̨̛̰̯͕͔́̐͗͌͟͠.̷̩̼̼̩̞̘̪́͗̅͊̎̾̅̏̀̕͟ͅ",
|
||||
@"This is some normal text",
|
||||
];
|
||||
|
||||
[TSStorageManager.sharedManager.dbReadWriteConnection
|
||||
readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
|
||||
for (NSString *string in strings) {
|
||||
DDLogInfo(@"%@ sending zalgo", self.logTag);
|
||||
|
||||
{
|
||||
TSIncomingMessage *message =
|
||||
[[TSIncomingMessage alloc] initWithTimestamp:[NSDate ows_millisecondTimeStamp]
|
||||
inThread:thread
|
||||
authorId:@"+19174054215"
|
||||
sourceDeviceId:0
|
||||
messageBody:string];
|
||||
[message saveWithTransaction:transaction];
|
||||
[message markAsReadWithTransaction:transaction sendReadReceipt:NO updateExpiration:NO];
|
||||
}
|
||||
{
|
||||
NSString *recipientId = @"+19174054215";
|
||||
NSString *groupName = string;
|
||||
NSMutableArray<NSString *> *recipientIds = [@[
|
||||
recipientId,
|
||||
[TSAccountManager localNumber],
|
||||
] mutableCopy];
|
||||
NSData *groupId = [SecurityUtils generateRandomBytes:16];
|
||||
TSGroupModel *groupModel =
|
||||
[[TSGroupModel alloc] initWithTitle:groupName memberIds:recipientIds image:nil groupId:groupId];
|
||||
|
||||
TSGroupThread *groupThread =
|
||||
[TSGroupThread getOrCreateThreadWithGroupModel:groupModel transaction:transaction];
|
||||
OWSAssert(groupThread);
|
||||
}
|
||||
}
|
||||
}];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
|
||||
@ -189,7 +189,7 @@ const NSUInteger kAvatarViewDiameter = 52;
|
||||
: [UIColor lightGrayColor]),
|
||||
}]];
|
||||
}
|
||||
NSString *displayableText = [DisplayableText filterText:thread.lastMessageLabel];
|
||||
NSString *displayableText = thread.lastMessageLabel.filterStringForDisplay;
|
||||
if (displayableText) {
|
||||
[snippetText appendAttributedString:[[NSAttributedString alloc]
|
||||
initWithString:displayableText
|
||||
|
||||
@ -10,6 +10,7 @@
|
||||
#import <SignalMessaging/NSString+OWS.h>
|
||||
#import <SignalMessaging/OWSContactsManager.h>
|
||||
#import <SignalMessaging/OWSPreferences.h>
|
||||
#import <SignalServiceKit/NSString+SSK.h>
|
||||
#import <SignalServiceKit/TSCall.h>
|
||||
#import <SignalServiceKit/TSContactThread.h>
|
||||
#import <SignalServiceKit/TSErrorMessage.h>
|
||||
@ -402,6 +403,8 @@ NSString *const kNotificationsManagerNewMesssageSoundName = @"NewMessage.aifc";
|
||||
|
||||
- (void)presentNotification:(UILocalNotification *)notification identifier:(NSString *)identifier
|
||||
{
|
||||
notification.alertBody = notification.alertBody.filterStringForDisplay;
|
||||
|
||||
DispatchMainThreadSafe(^{
|
||||
// Replace any existing notification
|
||||
// e.g. when an "Incoming Call" notification gets replaced with a "Missed Call" notification.
|
||||
|
||||
@ -11,6 +11,7 @@
|
||||
#import <SignalMessaging/OWSContactsManager.h>
|
||||
#import <SignalServiceKit/AppReadiness.h>
|
||||
#import <SignalServiceKit/NSDate+OWS.h>
|
||||
#import <SignalServiceKit/NSString+SSK.h>
|
||||
#import <SignalServiceKit/OWSDevice.h>
|
||||
#import <SignalServiceKit/OWSMessageReceiver.h>
|
||||
#import <SignalServiceKit/OWSMessageSender.h>
|
||||
@ -202,7 +203,8 @@ NSString *const Signal_Message_MarkAsRead_Identifier = @"Signal_Message_MarkAsRe
|
||||
|
||||
UILocalNotification *failedSendNotif = [[UILocalNotification alloc] init];
|
||||
failedSendNotif.alertBody =
|
||||
[NSString stringWithFormat:NSLocalizedString(@"NOTIFICATION_SEND_FAILED", nil), [thread name]];
|
||||
[NSString stringWithFormat:NSLocalizedString(@"NOTIFICATION_SEND_FAILED", nil), [thread name]]
|
||||
.filterStringForDisplay;
|
||||
failedSendNotif.userInfo = @{ Signal_Thread_UserInfo_Key : thread.uniqueId };
|
||||
[self presentNotification:failedSendNotif checkForCancel:NO];
|
||||
completionHandler();
|
||||
@ -446,6 +448,8 @@ NSString *const PushManagerUserInfoKeysCallBackSignalRecipientId = @"PushManager
|
||||
// TODO: consolidate notification tracking with NotificationsManager, which also maintains a list of notifications.
|
||||
- (void)presentNotification:(UILocalNotification *)notification checkForCancel:(BOOL)checkForCancel
|
||||
{
|
||||
notification.alertBody = notification.alertBody.filterStringForDisplay;
|
||||
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
NSString *threadId = notification.userInfo[Signal_Thread_UserInfo_Key];
|
||||
if (checkForCancel && threadId != nil) {
|
||||
|
||||
26
Signal/src/util/NSString+OWS.m
Normal file
26
Signal/src/util/NSString+OWS.m
Normal file
@ -0,0 +1,26 @@
|
||||
//
|
||||
// Copyright (c) 2018 Open Whisper Systems. All rights reserved.
|
||||
//
|
||||
|
||||
#import "NSString+OWS.h"
|
||||
#import "UIView+OWS.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@implementation NSString (OWS)
|
||||
|
||||
- (NSString *)rtlSafeAppend:(NSString *)string referenceView:(UIView *)referenceView
|
||||
{
|
||||
OWSAssert(string);
|
||||
OWSAssert(referenceView);
|
||||
|
||||
if ([referenceView isRTL]) {
|
||||
return [string stringByAppendingString:self];
|
||||
} else {
|
||||
return [self stringByAppendingString:string];
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
@ -21,20 +21,20 @@ class DisplayableTextTest: XCTestCase {
|
||||
func testDisplayableText() {
|
||||
// show plain text
|
||||
let boringText = "boring text"
|
||||
XCTAssertEqual(boringText, DisplayableText.displayableText(boringText).displayText)
|
||||
XCTAssertEqual(boringText, boringText.filterStringForDisplay())
|
||||
|
||||
// show high byte emojis
|
||||
let emojiText = "🇹🇹🌼🇹🇹🌼🇹🇹"
|
||||
XCTAssertEqual(emojiText, DisplayableText.displayableText(emojiText).displayText)
|
||||
XCTAssertEqual(emojiText, emojiText.filterStringForDisplay())
|
||||
|
||||
// show normal diacritic usage
|
||||
let diacriticalText = "Příliš žluťoučký kůň úpěl ďábelské ódy."
|
||||
XCTAssertEqual(diacriticalText, DisplayableText.displayableText(diacriticalText).displayText)
|
||||
XCTAssertEqual(diacriticalText, diacriticalText.filterStringForDisplay())
|
||||
|
||||
// filter excessive diacritics
|
||||
XCTAssertEqual("HAVING TROUBLE READING TEXT?", DisplayableText.displayableText("H҉̸̧͘͠A͢͞V̛̛I̴̸N͏̕͏G҉̵͜͏͢ ̧̧́T̶̛͘͡R̸̵̨̢̀O̷̡U͡҉B̶̛͢͞L̸̸͘͢͟É̸ ̸̛͘͏R͟È͠͞A̸͝Ḑ̕͘͜I̵͘҉͜͞N̷̡̢͠G̴͘͠ ͟͞T͏̢́͡È̀X̕҉̢̀T̢͠?̕͏̢͘͢").displayText )
|
||||
XCTAssertEqual("HAVING TROUBLE READING TEXT?", "H҉̸̧͘͠A͢͞V̛̛I̴̸N͏̕͏G҉̵͜͏͢ ̧̧́T̶̛͘͡R̸̵̨̢̀O̷̡U͡҉B̶̛͢͞L̸̸͘͢͟É̸ ̸̛͘͏R͟È͠͞A̸͝Ḑ̕͘͜I̵͘҉͜͞N̷̡̢͠G̴͘͠ ͟͞T͏̢́͡È̀X̕҉̢̀T̢͠?̕͏̢͘͢".filterStringForDisplay() )
|
||||
|
||||
XCTAssertEqual("LGO!", DisplayableText.displayableText("L̷̳͔̲͝Ģ̵̮̯̤̩̙͍̬̟͉̹̘̹͍͈̮̦̰̣͟͝O̶̴̮̻̮̗͘͡!̴̷̟͓͓").displayText)
|
||||
XCTAssertEqual("LGO!", "L̷̳͔̲͝Ģ̵̮̯̤̩̙͍̬̟͉̹̘̹͍͈̮̦̰̣͟͝O̶̴̮̻̮̗͘͡!̴̷̟͓͓".filterStringForDisplay())
|
||||
}
|
||||
|
||||
func testGlyphCount() {
|
||||
|
||||
@ -130,7 +130,7 @@ public class SignalAttachment: NSObject {
|
||||
|
||||
@objc
|
||||
public var sourceFilename: String? {
|
||||
return dataSource.sourceFilename
|
||||
return dataSource.sourceFilename?.filterStringForDisplay()
|
||||
}
|
||||
|
||||
@objc
|
||||
@ -311,7 +311,7 @@ public class SignalAttachment: NSObject {
|
||||
@objc
|
||||
public var filenameOrDefault: String {
|
||||
if let filename = sourceFilename {
|
||||
return filename
|
||||
return filename.filterStringForDisplay()
|
||||
} else {
|
||||
let kDefaultAttachmentName = "signal"
|
||||
|
||||
@ -335,7 +335,7 @@ public class SignalAttachment: NSObject {
|
||||
if let filename = sourceFilename {
|
||||
let fileExtension = (filename as NSString).pathExtension
|
||||
if fileExtension.count > 0 {
|
||||
return fileExtension
|
||||
return fileExtension.filterStringForDisplay()
|
||||
}
|
||||
}
|
||||
if isOversizeText {
|
||||
@ -567,7 +567,6 @@ public class SignalAttachment: NSObject {
|
||||
@objc
|
||||
private class func imageAttachment(dataSource: DataSource?, dataUTI: String, imageQuality: TSImageQuality) -> SignalAttachment {
|
||||
assert(dataUTI.count > 0)
|
||||
|
||||
assert(dataSource != nil)
|
||||
guard let dataSource = dataSource else {
|
||||
let attachment = SignalAttachment(dataSource : DataSourceValue.emptyDataSource(), dataUTI: dataUTI)
|
||||
|
||||
@ -2,12 +2,12 @@
|
||||
// Copyright (c) 2018 Open Whisper Systems. All rights reserved.
|
||||
//
|
||||
|
||||
#import <SignalServiceKit/NSString+SSK.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface NSString (OWS)
|
||||
|
||||
- (NSString *)ows_stripped;
|
||||
|
||||
- (NSString *)rtlSafeAppend:(NSString *)string referenceView:(UIView *)referenceView;
|
||||
- (NSString *)rtlSafeAppend:(NSString *)string isRTL:(BOOL)isRTL;
|
||||
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
//
|
||||
// Copyright (c) 2017 Open Whisper Systems. All rights reserved.
|
||||
// Copyright (c) 2018 Open Whisper Systems. All rights reserved.
|
||||
//
|
||||
|
||||
#import "OWSContactsManager.h"
|
||||
@ -13,6 +13,7 @@
|
||||
#import <SignalMessaging/UIFont+OWS.h>
|
||||
#import <SignalServiceKit/ContactsUpdater.h>
|
||||
#import <SignalServiceKit/NSNotificationCenter+OWS.h>
|
||||
#import <SignalServiceKit/NSString+SSK.h>
|
||||
#import <SignalServiceKit/OWSError.h>
|
||||
#import <SignalServiceKit/PhoneNumber.h>
|
||||
#import <SignalServiceKit/SignalAccount.h>
|
||||
@ -379,7 +380,7 @@ NSString *const OWSContactsManagerSignalAccountsDidChangeNotification
|
||||
OWSAssert(recipientId.length > 0);
|
||||
|
||||
SignalAccount *_Nullable signalAccount = [self signalAccountForRecipientId:recipientId];
|
||||
return signalAccount.contact.firstName;
|
||||
return signalAccount.contact.firstName.filterStringForDisplay;
|
||||
}
|
||||
|
||||
- (NSString *_Nullable)cachedLastNameForRecipientId:(NSString *)recipientId
|
||||
@ -387,7 +388,7 @@ NSString *const OWSContactsManagerSignalAccountsDidChangeNotification
|
||||
OWSAssert(recipientId.length > 0);
|
||||
|
||||
SignalAccount *_Nullable signalAccount = [self signalAccountForRecipientId:recipientId];
|
||||
return signalAccount.contact.lastName;
|
||||
return signalAccount.contact.lastName.filterStringForDisplay;
|
||||
}
|
||||
|
||||
#pragma mark - View Helpers
|
||||
@ -427,7 +428,7 @@ NSString *const OWSContactsManagerSignalAccountsDidChangeNotification
|
||||
indexText];
|
||||
}
|
||||
|
||||
return phoneNumberLabel;
|
||||
return phoneNumberLabel.filterStringForDisplay;
|
||||
}
|
||||
|
||||
- (BOOL)phoneNumber:(PhoneNumber *)phoneNumber1 matchesNumber:(PhoneNumber *)phoneNumber2
|
||||
|
||||
@ -200,24 +200,9 @@ extension String {
|
||||
|
||||
// MARK: Filter Methods
|
||||
|
||||
@objc
|
||||
public class func filterText(_ text: String?) -> String? {
|
||||
guard let text = text?.ows_stripped() else {
|
||||
return nil
|
||||
}
|
||||
|
||||
if (self.hasExcessiveDiacriticals(text: text)) {
|
||||
Logger.warn("\(TAG) filtering text for excessive diacriticals.")
|
||||
let filteredText = text.folding(options: .diacriticInsensitive, locale: .current)
|
||||
return filteredText.ows_stripped()
|
||||
}
|
||||
|
||||
return text.ows_stripped()
|
||||
}
|
||||
|
||||
@objc
|
||||
public class func filterNotificationText(_ text: String?) -> String? {
|
||||
guard let text = self.filterText(text) else {
|
||||
guard let text = text?.filterStringForDisplay() else {
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -229,25 +214,11 @@ extension String {
|
||||
return text.replacingOccurrences(of: "%", with: "%%")
|
||||
}
|
||||
|
||||
private class func hasExcessiveDiacriticals(text: String) -> Bool {
|
||||
// discard any zalgo style text, by detecting maximum number of glyphs per character
|
||||
for char in text.enumerated() {
|
||||
let scalarCount = String(char.element).unicodeScalars.count
|
||||
if scalarCount > 4 {
|
||||
Logger.warn("\(TAG) detected excessive diacriticals at \(char.element) scalarCount: \(scalarCount)")
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
@objc
|
||||
public class func displayableText(_ rawText: String) -> DisplayableText {
|
||||
// Only show up to N characters of text.
|
||||
let kMaxTextDisplayLength = 1024
|
||||
let filteredText = filterText(rawText)
|
||||
let fullText = filteredText != nil ? filteredText! : ""
|
||||
let fullText = rawText.filterStringForDisplay()
|
||||
var isTextTruncated = false
|
||||
var displayText = fullText
|
||||
if displayText.count > kMaxTextDisplayLength {
|
||||
|
||||
@ -1,9 +1,10 @@
|
||||
//
|
||||
// Copyright (c) 2017 Open Whisper Systems. All rights reserved.
|
||||
// Copyright (c) 2018 Open Whisper Systems. All rights reserved.
|
||||
//
|
||||
|
||||
#import "SignalAccount.h"
|
||||
#import "Contact.h"
|
||||
#import "NSString+SSK.h"
|
||||
#import "SignalRecipient.h"
|
||||
#import "TSStorageManager.h"
|
||||
|
||||
@ -58,7 +59,12 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
? [NSString stringWithFormat:@"%@ (%@)", baseName, self.multipleAccountLabelText]
|
||||
: baseName);
|
||||
|
||||
return displayName;
|
||||
return displayName.filterStringForDisplay;
|
||||
}
|
||||
|
||||
- (NSString *)multipleAccountLabelText
|
||||
{
|
||||
return _multipleAccountLabelText.filterStringForDisplay;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@ -1,9 +1,10 @@
|
||||
//
|
||||
// Copyright (c) 2017 Open Whisper Systems. All rights reserved.
|
||||
// Copyright (c) 2018 Open Whisper Systems. All rights reserved.
|
||||
//
|
||||
|
||||
#import "TSAttachment.h"
|
||||
#import "MIMETypeUtil.h"
|
||||
#import "NSString+SSK.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@ -13,6 +14,8 @@ NSUInteger const TSAttachmentSchemaVersion = 4;
|
||||
|
||||
@property (nonatomic, readonly) NSUInteger attachmentSchemaVersion;
|
||||
|
||||
@property (nonatomic, nullable) NSString *sourceFilename;
|
||||
|
||||
@end
|
||||
|
||||
@implementation TSAttachment
|
||||
@ -185,6 +188,16 @@ NSUInteger const TSAttachmentSchemaVersion = 4;
|
||||
return self.attachmentType == TSAttachmentTypeVoiceMessage;
|
||||
}
|
||||
|
||||
- (nullable NSString *)sourceFilename
|
||||
{
|
||||
return _sourceFilename.filterStringForDisplay;
|
||||
}
|
||||
|
||||
- (NSString *)contentType
|
||||
{
|
||||
return _contentType.filterStringForDisplay;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
|
||||
@ -1,9 +1,10 @@
|
||||
//
|
||||
// Copyright (c) 2017 Open Whisper Systems. All rights reserved.
|
||||
// Copyright (c) 2018 Open Whisper Systems. All rights reserved.
|
||||
//
|
||||
|
||||
#import "TSMessage.h"
|
||||
#import "NSDate+OWS.h"
|
||||
#import "NSString+SSK.h"
|
||||
#import "TSAttachment.h"
|
||||
#import "TSAttachmentPointer.h"
|
||||
#import "TSThread.h"
|
||||
@ -303,6 +304,11 @@ static const NSUInteger OWSMessageSchemaVersion = 4;
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (nullable NSString *)body
|
||||
{
|
||||
return _body.filterStringForDisplay;
|
||||
}
|
||||
|
||||
#pragma mark - Update With... Methods
|
||||
|
||||
- (void)updateWithExpireStartedAt:(uint64_t)expireStartedAt transaction:(YapDatabaseReadWriteTransaction *)transaction
|
||||
|
||||
@ -9,6 +9,7 @@
|
||||
#import "Cryptography.h"
|
||||
#import "MimeTypeUtil.h"
|
||||
#import "NSDate+OWS.h"
|
||||
#import "NSString+SSK.h"
|
||||
#import "NotificationsProtocol.h"
|
||||
#import "OWSAttachmentsProcessor.h"
|
||||
#import "OWSBlockingManager.h"
|
||||
@ -171,6 +172,13 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
DDLogInfo(@"%@ handling decrypted envelope: %@", self.logTag, [self descriptionForEnvelope:envelope]);
|
||||
|
||||
if (!envelope.source.isValidE164) {
|
||||
DDLogVerbose(
|
||||
@"%@ incoming envelope has invalid source: %@", self.logTag, [self descriptionForEnvelope:envelope]);
|
||||
OWSFail(@"%@ incoming envelope has invalid source", self.logTag);
|
||||
return;
|
||||
}
|
||||
|
||||
OWSAssert(envelope.source.length > 0);
|
||||
OWSAssert(![self isEnvelopeBlocked:envelope]);
|
||||
|
||||
@ -910,6 +918,15 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
if (groupId.length > 0) {
|
||||
NSMutableSet *newMemberIds = [NSMutableSet setWithArray:dataMessage.group.members];
|
||||
for (NSString *recipientId in newMemberIds) {
|
||||
if (!recipientId.isValidE164) {
|
||||
DDLogVerbose(@"%@ incoming group update has invalid group member: %@",
|
||||
self.logTag,
|
||||
[self descriptionForEnvelope:envelope]);
|
||||
OWSFail(@"%@ incoming group update has invalid group member", self.logTag);
|
||||
return nil;
|
||||
}
|
||||
}
|
||||
|
||||
// Group messages create the group if it doesn't already exist.
|
||||
//
|
||||
|
||||
@ -2,8 +2,8 @@
|
||||
// Copyright (c) 2018 Open Whisper Systems. All rights reserved.
|
||||
//
|
||||
|
||||
#import "TSYapDatabaseObject.h"
|
||||
#import "ContactsManagerProtocol.h"
|
||||
#import "TSYapDatabaseObject.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
|
||||
@ -4,9 +4,18 @@
|
||||
|
||||
#import "TSGroupModel.h"
|
||||
#import "FunctionalUtil.h"
|
||||
#import "NSString+SSK.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface TSGroupModel ()
|
||||
|
||||
@property (nullable, nonatomic) NSString *groupName;
|
||||
|
||||
@end
|
||||
|
||||
#pragma mark -
|
||||
|
||||
@implementation TSGroupModel
|
||||
|
||||
#if TARGET_OS_IOS
|
||||
@ -122,9 +131,13 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
return updatedGroupInfoString;
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
- (nullable NSString *)groupName
|
||||
{
|
||||
return _groupName.filterStringForDisplay;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
|
||||
@ -5,6 +5,7 @@
|
||||
#import "DataSource.h"
|
||||
#import "MIMETypeUtil.h"
|
||||
#import "NSData+Image.h"
|
||||
#import "NSString+SSK.h"
|
||||
#import "OWSFileSystem.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
@ -140,7 +141,7 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
return nil;
|
||||
}
|
||||
|
||||
NSData *data = [text dataUsingEncoding:NSUTF8StringEncoding];
|
||||
NSData *data = [text.filterStringForDisplay dataUsingEncoding:NSUTF8StringEncoding];
|
||||
return [self dataSourceWithData:data fileExtension:kOversizeTextAttachmentFileExtension];
|
||||
}
|
||||
|
||||
|
||||
17
SignalServiceKit/src/Util/NSString+SSK.h
Normal file
17
SignalServiceKit/src/Util/NSString+SSK.h
Normal file
@ -0,0 +1,17 @@
|
||||
//
|
||||
// Copyright (c) 2018 Open Whisper Systems. All rights reserved.
|
||||
//
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface NSString (SSK)
|
||||
|
||||
- (NSString *)ows_stripped;
|
||||
|
||||
- (NSString *)filterStringForDisplay;
|
||||
|
||||
- (BOOL)isValidE164;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
199
SignalServiceKit/src/Util/NSString+SSK.m
Normal file
199
SignalServiceKit/src/Util/NSString+SSK.m
Normal file
@ -0,0 +1,199 @@
|
||||
//
|
||||
// Copyright (c) 2018 Open Whisper Systems. All rights reserved.
|
||||
//
|
||||
|
||||
#import "NSString+SSK.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface UnicodeCodeRange : NSObject
|
||||
|
||||
@property (nonatomic) unichar first;
|
||||
@property (nonatomic) unichar last;
|
||||
|
||||
@end
|
||||
|
||||
#pragma mark -
|
||||
|
||||
@implementation UnicodeCodeRange
|
||||
|
||||
+ (UnicodeCodeRange *)rangeWithStart:(unichar)first last:(unichar)last
|
||||
{
|
||||
OWSAssert(first <= last);
|
||||
|
||||
UnicodeCodeRange *range = [UnicodeCodeRange new];
|
||||
range.first = first;
|
||||
range.last = last;
|
||||
return range;
|
||||
}
|
||||
|
||||
- (NSComparisonResult)compare:(UnicodeCodeRange *)other
|
||||
{
|
||||
|
||||
return self.first > other.first;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
#pragma mark -
|
||||
|
||||
@implementation NSString (SSK)
|
||||
|
||||
- (NSString *)ows_stripped
|
||||
{
|
||||
return [self stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
|
||||
}
|
||||
|
||||
+ (BOOL)shouldFilterIndic
|
||||
{
|
||||
static BOOL result = NO;
|
||||
static dispatch_once_t onceToken;
|
||||
dispatch_once(&onceToken, ^{
|
||||
result = (SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(11, 0) && !SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(11, 3));
|
||||
});
|
||||
return result;
|
||||
}
|
||||
|
||||
+ (BOOL)isIndicVowel:(unichar)c
|
||||
{
|
||||
static NSArray<UnicodeCodeRange *> *ranges;
|
||||
static dispatch_once_t onceToken;
|
||||
dispatch_once(&onceToken, ^{
|
||||
// From:
|
||||
// https://unicode.org/charts/PDF/U0C00.pdf
|
||||
// https://unicode.org/charts/PDF/U0980.pdf
|
||||
// https://unicode.org/charts/PDF/U0900.pdf
|
||||
ranges = [@[
|
||||
// Telugu:
|
||||
[UnicodeCodeRange rangeWithStart:0xC05 last:0xC14],
|
||||
[UnicodeCodeRange rangeWithStart:0xC3E last:0xC4C],
|
||||
[UnicodeCodeRange rangeWithStart:0xC60 last:0xC63],
|
||||
// Bengali
|
||||
[UnicodeCodeRange rangeWithStart:0x985 last:0x994],
|
||||
[UnicodeCodeRange rangeWithStart:0x9BE last:0x9C8],
|
||||
[UnicodeCodeRange rangeWithStart:0x9CB last:0x9CC],
|
||||
[UnicodeCodeRange rangeWithStart:0x9E0 last:0x9E3],
|
||||
// Devanagari
|
||||
[UnicodeCodeRange rangeWithStart:0x904 last:0x914],
|
||||
[UnicodeCodeRange rangeWithStart:0x93A last:0x93B],
|
||||
[UnicodeCodeRange rangeWithStart:0x93E last:0x94C],
|
||||
[UnicodeCodeRange rangeWithStart:0x94E last:0x94F],
|
||||
[UnicodeCodeRange rangeWithStart:0x955 last:0x957],
|
||||
[UnicodeCodeRange rangeWithStart:0x960 last:0x963],
|
||||
[UnicodeCodeRange rangeWithStart:0x972 last:0x977],
|
||||
] sortedArrayUsingSelector:@selector(compare:)];
|
||||
});
|
||||
|
||||
for (UnicodeCodeRange *range in ranges) {
|
||||
if (c < range.first) {
|
||||
// For perf, we can take advantage of the fact that the
|
||||
// ranges are sorted to exit early if the character lies
|
||||
// before the current range.
|
||||
return NO;
|
||||
}
|
||||
if (range.first <= c && c <= range.last) {
|
||||
return YES;
|
||||
}
|
||||
}
|
||||
return NO;
|
||||
}
|
||||
|
||||
+ (NSCharacterSet *)problematicCharacterSetForIndicScript
|
||||
{
|
||||
static NSCharacterSet *characterSet;
|
||||
static dispatch_once_t onceToken;
|
||||
dispatch_once(&onceToken, ^{
|
||||
UniChar chars[] = { 0x200C };
|
||||
NSString *characterSetString =
|
||||
[[NSString alloc] initWithCharacters:chars length:sizeof(chars) / sizeof(UniChar)];
|
||||
characterSet = [NSCharacterSet characterSetWithCharactersInString:characterSetString];
|
||||
});
|
||||
|
||||
return characterSet;
|
||||
}
|
||||
|
||||
// See: https://manishearth.github.io/blog/2018/02/15/picking-apart-the-crashing-ios-string/
|
||||
- (NSString *)filterForIndicScripts
|
||||
{
|
||||
if (!NSString.shouldFilterIndic) {
|
||||
return self;
|
||||
}
|
||||
|
||||
if ([self rangeOfCharacterFromSet:[[self class] problematicCharacterSetForIndicScript]].location == NSNotFound) {
|
||||
return self;
|
||||
}
|
||||
|
||||
NSMutableString *filteredForIndic = [NSMutableString new];
|
||||
for (NSUInteger index = 0; index < self.length; index++) {
|
||||
unichar c = [self characterAtIndex:index];
|
||||
if (c == 0x200C) {
|
||||
NSUInteger nextIndex = index + 1;
|
||||
if (nextIndex < self.length) {
|
||||
unichar next = [self characterAtIndex:nextIndex];
|
||||
if ([NSString isIndicVowel:next]) {
|
||||
// Discard ZWNJ (zero-width non-joiner) whenever we find a ZWNJ
|
||||
// followed by an Indic (Telugu, Bengali, Devanagari) vowel
|
||||
// and replace it with 0xFFFD, the Unicode "replacement character."
|
||||
[filteredForIndic appendFormat:@"\uFFFD"];
|
||||
DDLogError(@"%@ Filtered unsafe Indic script.", self.logTag);
|
||||
// Then discard the vowel too.
|
||||
index++;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
[filteredForIndic appendFormat:@"%C", c];
|
||||
}
|
||||
return [filteredForIndic copy];
|
||||
}
|
||||
|
||||
- (NSString *)filterStringForDisplay
|
||||
{
|
||||
return self.ows_stripped.filterForIndicScripts.filterForExcessiveDiacriticals;
|
||||
}
|
||||
|
||||
- (NSString *)filterForExcessiveDiacriticals
|
||||
{
|
||||
if (!self.hasExcessiveDiacriticals) {
|
||||
return self;
|
||||
}
|
||||
return [self stringByFoldingWithOptions:NSDiacriticInsensitiveSearch locale:[NSLocale currentLocale]];
|
||||
}
|
||||
|
||||
- (BOOL)hasExcessiveDiacriticals
|
||||
{
|
||||
// discard any zalgo style text, by detecting maximum number of glyphs per character
|
||||
NSUInteger index = 0;
|
||||
while (index < self.length) {
|
||||
// Walk the grapheme clusters in the string.
|
||||
NSRange range = [self rangeOfComposedCharacterSequenceAtIndex:index];
|
||||
if (range.length > 4) {
|
||||
// There are too many characters in this grapheme cluster.
|
||||
return YES;
|
||||
} else if (range.location != index || range.length < 1) {
|
||||
// This should never happen.
|
||||
OWSFail(
|
||||
@"%@ unexpected composed character sequence: %zd, %@", self.logTag, index, NSStringFromRange(range));
|
||||
return YES;
|
||||
}
|
||||
index = range.location + range.length;
|
||||
}
|
||||
return NO;
|
||||
}
|
||||
|
||||
- (BOOL)isValidE164
|
||||
{
|
||||
NSError *error = nil;
|
||||
NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:@"^\\+\\d+$"
|
||||
options:NSRegularExpressionCaseInsensitive
|
||||
error:&error];
|
||||
if (error || !regex) {
|
||||
OWSFail(@"%@ could not compile regex: %@", self.logTag, error);
|
||||
return NO;
|
||||
}
|
||||
return [regex rangeOfFirstMatchInString:self options:0 range:NSMakeRange(0, self.length)].location != NSNotFound;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
Loading…
Reference in New Issue
Block a user