Address Indic script crash.
This commit is contained in:
parent
c60422e921
commit
abfd333a17
|
@ -38,7 +38,7 @@
|
|||
<key>CFBundlePackageType</key>
|
||||
<string>APPL</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>2.19.5</string>
|
||||
<string>2.19.7</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<key>CFBundleURLTypes</key>
|
||||
|
@ -55,7 +55,7 @@
|
|||
</dict>
|
||||
</array>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>2.19.5.0</string>
|
||||
<string>2.19.7.3</string>
|
||||
<key>ITSAppUsesNonExemptEncryption</key>
|
||||
<false/>
|
||||
<key>LOGS_EMAIL</key>
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
//
|
||||
// Copyright (c) 2017 Open Whisper Systems. All rights reserved.
|
||||
// Copyright (c) 2018 Open Whisper Systems. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
@ -91,7 +91,7 @@ class SignalAttachment: NSObject {
|
|||
return dataSource.dataUrl()
|
||||
}
|
||||
public var sourceFilename: String? {
|
||||
return dataSource.sourceFilename
|
||||
return dataSource.sourceFilename?.filterStringForDisplay()
|
||||
}
|
||||
public var isValidImage: Bool {
|
||||
return dataSource.isValidImage()
|
||||
|
@ -223,7 +223,7 @@ class SignalAttachment: NSObject {
|
|||
|
||||
if let filename = sourceFilename {
|
||||
let fileExtension = (filename as NSString).pathExtension
|
||||
if fileExtension.characters.count > 0 {
|
||||
if fileExtension.count > 0 {
|
||||
if let mimeType = MIMETypeUtil.mimeType(forFileExtension:fileExtension) {
|
||||
// UTI types are an imperfect means of representing file type;
|
||||
// file extensions are also imperfect but far more reliable and
|
||||
|
@ -249,7 +249,7 @@ class SignalAttachment: NSObject {
|
|||
// like: "signal-2017-04-24-095918.zip"
|
||||
var filenameOrDefault: String {
|
||||
if let filename = sourceFilename {
|
||||
return filename
|
||||
return filename.filterStringForDisplay()
|
||||
} else {
|
||||
let kDefaultAttachmentName = "signal"
|
||||
|
||||
|
@ -271,8 +271,8 @@ class SignalAttachment: NSObject {
|
|||
var fileExtension: String? {
|
||||
if let filename = sourceFilename {
|
||||
let fileExtension = (filename as NSString).pathExtension
|
||||
if fileExtension.characters.count > 0 {
|
||||
return fileExtension
|
||||
if fileExtension.count > 0 {
|
||||
return fileExtension.filterStringForDisplay()
|
||||
}
|
||||
}
|
||||
if dataUTI == kOversizeTextAttachmentUTI {
|
||||
|
@ -475,7 +475,7 @@ class SignalAttachment: NSObject {
|
|||
// NOTE: The attachment returned by this method may not be valid.
|
||||
// Check the attachment's error property.
|
||||
private class func imageAttachment(dataSource: DataSource?, dataUTI: String) -> SignalAttachment {
|
||||
assert(dataUTI.characters.count > 0)
|
||||
assert(dataUTI.count > 0)
|
||||
|
||||
assert(dataSource != nil)
|
||||
guard let dataSource = dataSource else {
|
||||
|
@ -575,7 +575,7 @@ class SignalAttachment: NSObject {
|
|||
// NOTE: The attachment returned by this method may nil or not be valid.
|
||||
// Check the attachment's error property.
|
||||
public class func imageAttachment(image: UIImage?, dataUTI: String, filename: String?) -> SignalAttachment {
|
||||
assert(dataUTI.characters.count > 0)
|
||||
assert(dataUTI.count > 0)
|
||||
|
||||
guard let image = image else {
|
||||
let dataSource = DataSourceValue.emptyDataSource()
|
||||
|
@ -777,7 +777,7 @@ class SignalAttachment: NSObject {
|
|||
dataUTI: String,
|
||||
validUTISet: Set<String>?,
|
||||
maxFileSize: UInt) -> SignalAttachment {
|
||||
assert(dataUTI.characters.count > 0)
|
||||
assert(dataUTI.count > 0)
|
||||
|
||||
assert(dataSource != nil)
|
||||
guard let dataSource = dataSource else {
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
//
|
||||
// Copyright (c) 2017 Open Whisper Systems. All rights reserved.
|
||||
// Copyright (c) 2018 Open Whisper Systems. All rights reserved.
|
||||
//
|
||||
|
||||
#import "OWSProfileManager.h"
|
||||
|
@ -11,6 +11,7 @@
|
|||
#import <SignalServiceKit/NSData+hexString.h>
|
||||
#import <SignalServiceKit/NSDate+OWS.h>
|
||||
#import <SignalServiceKit/NSNotificationCenter+OWS.h>
|
||||
#import <SignalServiceKit/NSString+SSK.h>
|
||||
#import <SignalServiceKit/OWSFileSystem.h>
|
||||
#import <SignalServiceKit/OWSMessageSender.h>
|
||||
#import <SignalServiceKit/OWSRequestBuilder.h>
|
||||
|
@ -70,7 +71,7 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
{
|
||||
@synchronized(self)
|
||||
{
|
||||
return _profileName;
|
||||
return _profileName.filterStringForDisplay;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -78,7 +79,7 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
{
|
||||
@synchronized(self)
|
||||
{
|
||||
_profileName = [profileName ows_stripped];
|
||||
_profileName = profileName.filterStringForDisplay;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -364,6 +365,8 @@ const NSUInteger kOWSProfileManager_MaxAvatarDiameter = 640;
|
|||
OWSAssert(successBlockParameter);
|
||||
OWSAssert(failureBlockParameter);
|
||||
|
||||
profileName = profileName.filterStringForDisplay;
|
||||
|
||||
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
|
||||
@synchronized(self)
|
||||
{
|
||||
|
@ -1327,7 +1330,7 @@ const NSUInteger kOWSProfileManager_MaxAvatarDiameter = 640;
|
|||
|
||||
NSData *unpaddedData = [decryptedData subdataWithRange:NSMakeRange(0, unpaddedLength)];
|
||||
|
||||
return [[NSString alloc] initWithData:unpaddedData encoding:NSUTF8StringEncoding];
|
||||
return [[NSString alloc] initWithData:unpaddedData encoding:NSUTF8StringEncoding].filterStringForDisplay;
|
||||
}
|
||||
|
||||
- (nullable NSData *)encryptProfileData:(nullable NSData *)data
|
||||
|
@ -1345,7 +1348,7 @@ const NSUInteger kOWSProfileManager_MaxAvatarDiameter = 640;
|
|||
|
||||
- (nullable NSData *)encryptProfileNameWithUnpaddedName:(NSString *)name
|
||||
{
|
||||
NSData *nameData = [name dataUsingEncoding:NSUTF8StringEncoding];
|
||||
NSData *nameData = [name.filterStringForDisplay dataUsingEncoding:NSUTF8StringEncoding];
|
||||
if (nameData.length > kOWSProfileManager_NameDataLength) {
|
||||
OWSFail(@"%@ name data is too long with length:%lu", self.logTag, (unsigned long)nameData.length);
|
||||
return nil;
|
||||
|
|
|
@ -10,8 +10,8 @@
|
|||
#import "DebugUIPage.h"
|
||||
#import "Environment.h"
|
||||
#import "FingerprintViewController.h"
|
||||
#import "MediaDetailViewController.h"
|
||||
#import "HomeViewController.h"
|
||||
#import "MediaDetailViewController.h"
|
||||
#import "NSString+OWS.h"
|
||||
#import "NotificationsManager.h"
|
||||
#import "OWSAnyTouchGestureRecognizer.h"
|
||||
|
@ -62,6 +62,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>
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
//
|
||||
// Copyright (c) 2017 Open Whisper Systems. All rights reserved.
|
||||
// Copyright (c) 2018 Open Whisper Systems. All rights reserved.
|
||||
//
|
||||
|
||||
#import "ConversationViewItem.h"
|
||||
|
@ -309,7 +309,7 @@ NSString *NSStringForOWSMessageCellType(OWSMessageCellType cellType)
|
|||
|
||||
// Only show up to N characters of text.
|
||||
const NSUInteger kMaxTextDisplayLength = 1024;
|
||||
NSString *_Nullable fullText = [DisplayableText displayableText:text];
|
||||
NSString *_Nullable fullText = text.filterStringForDisplay;
|
||||
BOOL isTextTruncated = NO;
|
||||
if (!fullText) {
|
||||
fullText = @"";
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
//
|
||||
// Copyright (c) 2017 Open Whisper Systems. All rights reserved.
|
||||
// Copyright (c) 2018 Open Whisper Systems. All rights reserved.
|
||||
//
|
||||
|
||||
#import "DebugUIMessages.h"
|
||||
|
@ -249,6 +249,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;
|
||||
|
@ -1431,6 +1439,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
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
//
|
||||
// Copyright (c) 2017 Open Whisper Systems. All rights reserved.
|
||||
// Copyright (c) 2018 Open Whisper Systems. All rights reserved.
|
||||
//
|
||||
|
||||
#import "DebugUIMisc.h"
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
//
|
||||
// Copyright (c) 2017 Open Whisper Systems. All rights reserved.
|
||||
// Copyright (c) 2018 Open Whisper Systems. All rights reserved.
|
||||
//
|
||||
|
||||
#import "InboxTableViewCell.h"
|
||||
|
@ -188,7 +188,7 @@ const NSUInteger kAvatarViewDiameter = 52;
|
|||
: [UIColor lightGrayColor]),
|
||||
}]];
|
||||
}
|
||||
NSString *displayableText = [DisplayableText displayableText:thread.lastMessageLabel];
|
||||
NSString *displayableText = thread.lastMessageLabel.filterStringForDisplay;
|
||||
if (displayableText) {
|
||||
[snippetText appendAttributedString:[[NSAttributedString alloc]
|
||||
initWithString:displayableText
|
||||
|
|
|
@ -312,7 +312,7 @@ class MessageDetailViewController: OWSViewController, UIScrollViewDelegate {
|
|||
return nil
|
||||
}
|
||||
let messageBody = displayableText.fullText
|
||||
guard messageBody.characters.count > 0 else {
|
||||
guard messageBody.count > 0 else {
|
||||
return nil
|
||||
}
|
||||
return messageBody
|
||||
|
@ -500,7 +500,7 @@ class MessageDetailViewController: OWSViewController, UIScrollViewDelegate {
|
|||
nameLabel.autoPinEdge(toSuperviewEdge: .top)
|
||||
valueLabel.autoPinEdge(toSuperviewEdge: .top)
|
||||
|
||||
if subtitle.characters.count > 0 {
|
||||
if subtitle.count > 0 {
|
||||
let subtitleLabel = self.valueLabel(text: subtitle)
|
||||
subtitleLabel.textColor = UIColor.ows_darkGray()
|
||||
row.addSubview(subtitleLabel)
|
||||
|
@ -508,7 +508,7 @@ class MessageDetailViewController: OWSViewController, UIScrollViewDelegate {
|
|||
subtitleLabel.autoPinLeading(toTrailingOf: nameLabel, margin: 10)
|
||||
subtitleLabel.autoPinEdge(.top, to: .bottom, of: valueLabel, withOffset: 1)
|
||||
subtitleLabel.autoPinEdge(toSuperviewEdge: .bottom)
|
||||
} else if value.characters.count > 0 {
|
||||
} else if value.count > 0 {
|
||||
valueLabel.autoPinEdge(toSuperviewEdge: .bottom)
|
||||
} else {
|
||||
nameLabel.autoPinEdge(toSuperviewEdge: .bottom)
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
//
|
||||
// Copyright (c) 2017 Open Whisper Systems. All rights reserved.
|
||||
// Copyright (c) 2018 Open Whisper Systems. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
|
|
@ -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"
|
||||
|
@ -10,6 +10,7 @@
|
|||
#import "ViewControllerUtils.h"
|
||||
#import <SignalServiceKit/ContactsUpdater.h>
|
||||
#import <SignalServiceKit/NSNotificationCenter+OWS.h>
|
||||
#import <SignalServiceKit/NSString+SSK.h>
|
||||
#import <SignalServiceKit/OWSError.h>
|
||||
#import <SignalServiceKit/SignalAccount.h>
|
||||
#import <SignalServiceKit/TSStorageManager.h>
|
||||
|
@ -372,7 +373,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
|
||||
|
@ -380,7 +381,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
|
||||
|
@ -420,7 +421,7 @@ NSString *const OWSContactsManagerSignalAccountsDidChangeNotification
|
|||
indexText];
|
||||
}
|
||||
|
||||
return phoneNumberLabel;
|
||||
return phoneNumberLabel.filterStringForDisplay;
|
||||
}
|
||||
|
||||
- (BOOL)phoneNumber:(PhoneNumber *)phoneNumber1 matchesNumber:(PhoneNumber *)phoneNumber2 {
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
//
|
||||
// Copyright (c) 2017 Open Whisper Systems. All rights reserved.
|
||||
// Copyright (c) 2018 Open Whisper Systems. All rights reserved.
|
||||
//
|
||||
|
||||
#import "NotificationsManager.h"
|
||||
|
@ -10,6 +10,7 @@
|
|||
#import "PushManager.h"
|
||||
#import "Signal-Swift.h"
|
||||
#import <AudioToolbox/AudioServices.h>
|
||||
#import <SignalServiceKit/NSString+SSK.h>
|
||||
#import <SignalServiceKit/TSCall.h>
|
||||
#import <SignalServiceKit/TSContactThread.h>
|
||||
#import <SignalServiceKit/TSErrorMessage.h>
|
||||
|
@ -393,6 +394,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.
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
//
|
||||
// Copyright (c) 2017 Open Whisper Systems. All rights reserved.
|
||||
// Copyright (c) 2018 Open Whisper Systems. All rights reserved.
|
||||
//
|
||||
|
||||
#import "PushManager.h"
|
||||
|
@ -9,6 +9,7 @@
|
|||
#import "Signal-Swift.h"
|
||||
#import "ThreadUtil.h"
|
||||
#import <SignalServiceKit/NSDate+OWS.h>
|
||||
#import <SignalServiceKit/NSString+SSK.h>
|
||||
#import <SignalServiceKit/OWSDevice.h>
|
||||
#import <SignalServiceKit/OWSMessageReceiver.h>
|
||||
#import <SignalServiceKit/OWSMessageSender.h>
|
||||
|
@ -194,7 +195,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();
|
||||
|
@ -438,6 +440,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) {
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
//
|
||||
// Copyright (c) 2017 Open Whisper Systems. All rights reserved.
|
||||
// Copyright (c) 2018 Open Whisper Systems. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
@ -185,7 +185,7 @@ extension String {
|
|||
if string == "" {
|
||||
return 0
|
||||
}
|
||||
if string.characters.count > Int(kMaxJumbomojiCount * kMaxCharactersPerEmojiCount) {
|
||||
if string.count > Int(kMaxJumbomojiCount * kMaxCharactersPerEmojiCount) {
|
||||
return 0
|
||||
}
|
||||
guard string.containsOnlyEmoji else {
|
||||
|
@ -197,34 +197,4 @@ extension String {
|
|||
}
|
||||
return UInt(emojiCount)
|
||||
}
|
||||
|
||||
// MARK: Filter Methods
|
||||
|
||||
@objc
|
||||
class func displayableText(_ 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()
|
||||
}
|
||||
|
||||
private class func hasExcessiveDiacriticals(text: String) -> Bool {
|
||||
// discard any zalgo style text, by detecting maximum number of glyphs per character
|
||||
for char in text.characters.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
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,13 +1,13 @@
|
|||
//
|
||||
// Copyright (c) 2017 Open Whisper Systems. All rights reserved.
|
||||
// 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;
|
||||
|
||||
@end
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
//
|
||||
// Copyright (c) 2017 Open Whisper Systems. All rights reserved.
|
||||
// Copyright (c) 2018 Open Whisper Systems. All rights reserved.
|
||||
//
|
||||
|
||||
#import "NSString+OWS.h"
|
||||
|
@ -9,11 +9,6 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
|
||||
@implementation NSString (OWS)
|
||||
|
||||
- (NSString *)ows_stripped
|
||||
{
|
||||
return [self stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
|
||||
}
|
||||
|
||||
- (NSString *)rtlSafeAppend:(NSString *)string referenceView:(UIView *)referenceView
|
||||
{
|
||||
OWSAssert(string);
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
//
|
||||
// Copyright (c) 2017 Open Whisper Systems. All rights reserved.
|
||||
// Copyright (c) 2018 Open Whisper Systems. All rights reserved.
|
||||
//
|
||||
|
||||
import XCTest
|
||||
|
@ -19,20 +19,20 @@ class DisplayableTextTest: XCTestCase {
|
|||
func testDisplayableText() {
|
||||
// show plain text
|
||||
let boringText = "boring text"
|
||||
XCTAssertEqual(boringText, DisplayableText.displayableText(boringText))
|
||||
XCTAssertEqual(boringText, boringText.filterStringForDisplay())
|
||||
|
||||
// show high byte emojis
|
||||
let emojiText = "🇹🇹🌼🇹🇹🌼🇹🇹"
|
||||
XCTAssertEqual(emojiText, DisplayableText.displayableText(emojiText))
|
||||
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))
|
||||
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̢͠?̕͏̢͘͢") )
|
||||
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̶̴̮̻̮̗͘͡!̴̷̟͓͓"))
|
||||
XCTAssertEqual("LGO!", "L̷̳͔̲͝Ģ̵̮̯̤̩̙͍̬̟͉̹̘̹͍͈̮̦̰̣͟͝O̶̴̮̻̮̗͘͡!̴̷̟͓͓".filterStringForDisplay())
|
||||
}
|
||||
|
||||
func testGlyphCount() {
|
||||
|
|
|
@ -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
|
||||
|
@ -184,6 +187,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"
|
||||
|
@ -281,6 +282,11 @@ static const NSUInteger OWSMessageSchemaVersion = 3;
|
|||
return YES;
|
||||
}
|
||||
|
||||
- (nullable NSString *)body
|
||||
{
|
||||
return _body.filterStringForDisplay;
|
||||
}
|
||||
|
||||
#pragma mark - Update With... Methods
|
||||
|
||||
- (void)updateWithExpireStartedAt:(uint64_t)expireStartedAt transaction:(YapDatabaseReadWriteTransaction *)transaction
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
//
|
||||
// Copyright (c) 2017 Open Whisper Systems. All rights reserved.
|
||||
// Copyright (c) 2018 Open Whisper Systems. All rights reserved.
|
||||
//
|
||||
|
||||
#import "OWSMessageManager.h"
|
||||
|
@ -7,6 +7,7 @@
|
|||
#import "Cryptography.h"
|
||||
#import "MimeTypeUtil.h"
|
||||
#import "NSDate+OWS.h"
|
||||
#import "NSString+SSK.h"
|
||||
#import "NotificationsProtocol.h"
|
||||
#import "OWSAttachmentsProcessor.h"
|
||||
#import "OWSBlockingManager.h"
|
||||
|
@ -152,6 +153,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]);
|
||||
|
||||
|
@ -880,6 +888,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.
|
||||
//
|
||||
|
|
|
@ -1,15 +1,15 @@
|
|||
//
|
||||
// Copyright (c) 2017 Open Whisper Systems. All rights reserved.
|
||||
// Copyright (c) 2018 Open Whisper Systems. All rights reserved.
|
||||
//
|
||||
|
||||
#import "TSYapDatabaseObject.h"
|
||||
#import "ContactsManagerProtocol.h"
|
||||
#import "TSYapDatabaseObject.h"
|
||||
|
||||
@interface TSGroupModel : TSYapDatabaseObject
|
||||
|
||||
@property (nonatomic, strong) NSArray<NSString *> *groupMemberIds;
|
||||
@property (nonatomic, strong) NSString *groupName;
|
||||
@property (nonatomic, strong) NSData *groupId;
|
||||
@property (nonatomic) NSArray<NSString *> *groupMemberIds;
|
||||
@property (nonatomic) NSString *groupName;
|
||||
@property (nonatomic) NSData *groupId;
|
||||
|
||||
#if TARGET_OS_IOS
|
||||
@property (nonatomic, strong) UIImage *groupImage;
|
||||
|
|
|
@ -1,9 +1,10 @@
|
|||
//
|
||||
// Copyright (c) 2017 Open Whisper Systems. All rights reserved.
|
||||
// Copyright (c) 2018 Open Whisper Systems. All rights reserved.
|
||||
//
|
||||
|
||||
#import "TSGroupModel.h"
|
||||
#import "FunctionalUtil.h"
|
||||
#import "NSString+SSK.h"
|
||||
|
||||
@implementation TSGroupModel
|
||||
|
||||
|
@ -102,7 +103,11 @@
|
|||
return updatedGroupInfoString;
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
- (NSString *)groupName
|
||||
{
|
||||
return _groupName.filterStringForDisplay;
|
||||
}
|
||||
|
||||
@end
|
||||
|
|
|
@ -1,10 +1,11 @@
|
|||
//
|
||||
// Copyright (c) 2017 Open Whisper Systems. All rights reserved.
|
||||
// Copyright (c) 2018 Open Whisper Systems. All rights reserved.
|
||||
//
|
||||
|
||||
#import "DataSource.h"
|
||||
#import "MIMETypeUtil.h"
|
||||
#import "NSData+Image.h"
|
||||
#import "NSString+SSK.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
|
@ -139,7 +140,7 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
return nil;
|
||||
}
|
||||
|
||||
NSData *data = [text dataUsingEncoding:NSUTF8StringEncoding];
|
||||
NSData *data = [text.filterStringForDisplay dataUsingEncoding:NSUTF8StringEncoding];
|
||||
return [self dataSourceWithData:data fileExtension:kOversizeTextAttachmentFileExtension];
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
|
@ -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