diff --git a/Signal/src/Profiles/OWSProfileManager.h b/Signal/src/Profiles/OWSProfileManager.h index 175371572..8a7bd3e74 100644 --- a/Signal/src/Profiles/OWSProfileManager.h +++ b/Signal/src/Profiles/OWSProfileManager.h @@ -14,6 +14,7 @@ extern NSString *const kNSNotificationKey_ProfileRecipientId; extern NSString *const kNSNotificationKey_ProfileGroupId; extern const NSUInteger kOWSProfileManager_MaxAvatarDiameter; +extern const NSUInteger kOWSProfileManager_NameDataLength; @class TSThread; @class OWSAES256Key; diff --git a/Signal/src/Profiles/OWSProfileManager.m b/Signal/src/Profiles/OWSProfileManager.m index 5ef2fac70..822fdd627 100644 --- a/Signal/src/Profiles/OWSProfileManager.m +++ b/Signal/src/Profiles/OWSProfileManager.m @@ -99,7 +99,7 @@ NSString *const kOWSProfileManager_GroupWhitelistCollection = @"kOWSProfileManag // The max bytes for a user's profile name, encoded in UTF8. // Before encrypting and submitting we NULL pad the name data to this length. -static const NSUInteger kOWSProfileManager_NameDataLength = 26; +const NSUInteger kOWSProfileManager_NameDataLength = 26; const NSUInteger kOWSProfileManager_MaxAvatarDiameter = 640; @interface OWSProfileManager () diff --git a/Signal/src/ViewControllers/ProfileViewController.m b/Signal/src/ViewControllers/ProfileViewController.m index d9f820351..8d09af086 100644 --- a/Signal/src/ViewControllers/ProfileViewController.m +++ b/Signal/src/ViewControllers/ProfileViewController.m @@ -448,12 +448,52 @@ NSString *const kProfileView_LastPresentedDate = @"kProfileView_LastPresentedDat #pragma mark - UITextFieldDelegate - (BOOL)textField:(UITextField *)textField - shouldChangeCharactersInRange:(NSRange)range + shouldChangeCharactersInRange:(NSRange)editingRange replacementString:(NSString *)insertionText { // TODO: Possibly filter invalid input. - // TODO: Possibly prevent user from typing overlong name. - return YES; + + // Prevent crashing undo bug + if (editingRange.length + editingRange.location > textField.text.length) { + return NO; + } + + NSUInteger (^byteLength)(NSString *) = ^NSUInteger(NSString *string) { + if (string == nil) { + return 0; + } + + return [string dataUsingEncoding:NSUTF8StringEncoding].length; + }; + + NSUInteger lengthOfRemainingExistingString + = byteLength(textField.text) - byteLength([textField.text substringWithRange:editingRange]); + NSUInteger newLength = lengthOfRemainingExistingString + byteLength(insertionText); + + DDLogVerbose(@"%@ newLength: %lu", self.tag, (unsigned long)newLength); + if (newLength <= kOWSProfileManager_NameDataLength) { + return YES; + } + + // Don't allow any change if inserting a single char (typically this means typing) + if (insertionText.length < 2) { + return NO; + } + + // However if pasting, accept as much of the string as possible. + NSUInteger availableSpace = kOWSProfileManager_NameDataLength - lengthOfRemainingExistingString; + + NSString *acceptableSubstring = @""; + for (NSUInteger i = 0; i <= insertionText.length; i++) { + NSString *maybeAcceptableSubstring = [insertionText substringWithRange:NSMakeRange(0, i)]; + if (byteLength(maybeAcceptableSubstring) <= availableSpace) { + acceptableSubstring = maybeAcceptableSubstring; + } + } + textField.text = [textField.text stringByReplacingCharactersInRange:editingRange withString:acceptableSubstring]; + + // We've already handled any valid editing manually, so prevent further changes. + return NO; } - (BOOL)textFieldShouldReturn:(UITextField *)textField