From 46d944740b800556f5faec6e8d809558cf88d1f0 Mon Sep 17 00:00:00 2001 From: Michael Kirk Date: Fri, 2 Mar 2018 16:32:15 -0500 Subject: [PATCH 01/16] Make default audio tone more prominent Label Note as (default) Move it to the second item in the list, just after "None" // FREEBIE --- .../OWSSoundSettingsViewController.m | 16 ++++++++++++++-- Signal/translations/en.lproj/Localizable.strings | 3 +++ SignalMessaging/environment/OWSSounds.m | 13 ++++++------- .../migrations/OWSDatabaseMigrationRunner.m | 5 +---- 4 files changed, 24 insertions(+), 13 deletions(-) diff --git a/Signal/src/ViewControllers/OWSSoundSettingsViewController.m b/Signal/src/ViewControllers/OWSSoundSettingsViewController.m index ce7be75b2..0246644e1 100644 --- a/Signal/src/ViewControllers/OWSSoundSettingsViewController.m +++ b/Signal/src/ViewControllers/OWSSoundSettingsViewController.m @@ -74,13 +74,25 @@ NS_ASSUME_NONNULL_BEGIN for (NSNumber *nsValue in allSounds) { OWSSound sound = (OWSSound)nsValue.intValue; OWSTableItem *item; + + NSString *soundLabelText = ^{ + NSString *baseName = [OWSSounds displayNameForSound:sound]; + if (sound == OWSSound_Note) { + NSString *noteStringFormat = NSLocalizedString(@"SETTINGS_AUDIO_DEFAULT_TONE_LABEL_FORMAT", + @"Format string for the default 'Note' sound. Embeds the system {{sound name}}."); + return [NSString stringWithFormat:noteStringFormat, baseName]; + } else { + return [OWSSounds displayNameForSound:sound]; + } + }(); + if (sound == self.currentSound) { - item = [OWSTableItem checkmarkItemWithText:[OWSSounds displayNameForSound:sound] + item = [OWSTableItem checkmarkItemWithText:soundLabelText actionBlock:^{ [weakSelf soundWasSelected:sound]; }]; } else { - item = [OWSTableItem actionItemWithText:[OWSSounds displayNameForSound:sound] + item = [OWSTableItem actionItemWithText:soundLabelText actionBlock:^{ [weakSelf soundWasSelected:sound]; }]; diff --git a/Signal/translations/en.lproj/Localizable.strings b/Signal/translations/en.lproj/Localizable.strings index 0d37bc14c..c68e554da 100644 --- a/Signal/translations/en.lproj/Localizable.strings +++ b/Signal/translations/en.lproj/Localizable.strings @@ -1512,6 +1512,9 @@ /* No comment provided by engineer. */ "SETTINGS_ADVANCED_TITLE" = "Advanced"; +/* Format string for the default 'Note' sound. Embeds the system {{sound name}}. */ +"SETTINGS_AUDIO_DEFAULT_TONE_LABEL_FORMAT" = "%@ (default)"; + /* A label for the 'add phone number' button in the block list table. */ "SETTINGS_BLOCK_LIST_ADD_BUTTON" = "Add…"; diff --git a/SignalMessaging/environment/OWSSounds.m b/SignalMessaging/environment/OWSSounds.m index 54140475b..f1d3ea054 100644 --- a/SignalMessaging/environment/OWSSounds.m +++ b/SignalMessaging/environment/OWSSounds.m @@ -62,8 +62,9 @@ NSString *const kOWSSoundsStorageGlobalNotificationKey = @"kOWSSoundsStorageGlob + (NSArray *)allNotificationSounds { return @[ - // None should be first. + // None and Note (default) should be first. @(OWSSound_None), + @(OWSSound_Note), @(OWSSound_Aurora), @(OWSSound_Bamboo), @@ -74,7 +75,6 @@ NSString *const kOWSSoundsStorageGlobalNotificationKey = @"kOWSSoundsStorageGlob @(OWSSound_Hello), @(OWSSound_Input), @(OWSSound_Keys), - @(OWSSound_Note), @(OWSSound_Popcorn), @(OWSSound_Pulse), @(OWSSound_Synth), @@ -89,7 +89,7 @@ NSString *const kOWSSoundsStorageGlobalNotificationKey = @"kOWSSoundsStorageGlob OWSFail(@"%@ invalid argument.", self.logTag); return @""; - // Notification Sounds + // Notification Sounds case OWSSound_Aurora: return @"Aurora"; case OWSSound_Bamboo: @@ -117,11 +117,9 @@ NSString *const kOWSSoundsStorageGlobalNotificationKey = @"kOWSSoundsStorageGlob case OWSSound_ClassicNotification: return @"Classic"; - // Ringtone Sounds + // Call Audio case OWSSound_Opening: return @"Opening"; - - // Calls case OWSSound_CallConnecting: return @"Call Connecting"; case OWSSound_CallOutboundRinging: @@ -131,7 +129,7 @@ NSString *const kOWSSoundsStorageGlobalNotificationKey = @"kOWSSoundsStorageGlob case OWSSound_CallFailure: return @"Call Failure"; - // Other + // Other case OWSSound_None: return NSLocalizedString(@"SOUNDS_NONE", @"Label for the 'no sound' option that allows users to disable sounds for notifications, " @@ -286,6 +284,7 @@ NSString *const kOWSSoundsStorageGlobalNotificationKey = @"kOWSSoundsStorageGlob { OWSAssert(transaction); + DDLogInfo(@"%@ Setting global notification sound to: %s", sound); [transaction setObject:@(sound) forKey:kOWSSoundsStorageGlobalNotificationKey inCollection:kOWSSoundsStorageNotificationCollection]; diff --git a/SignalMessaging/environment/migrations/OWSDatabaseMigrationRunner.m b/SignalMessaging/environment/migrations/OWSDatabaseMigrationRunner.m index cfec11736..8ae0f01eb 100644 --- a/SignalMessaging/environment/migrations/OWSDatabaseMigrationRunner.m +++ b/SignalMessaging/environment/migrations/OWSDatabaseMigrationRunner.m @@ -65,10 +65,7 @@ NS_ASSUME_NONNULL_BEGIN NSMutableArray *migrationsToRun = [NSMutableArray new]; for (OWSDatabaseMigration *migration in migrations) { - if ([OWSDatabaseMigration fetchObjectWithUniqueID:migration.uniqueId]) { - DDLogDebug(@"%@ Skipping previously run migration: %@", self.logTag, migration); - } else { - DDLogWarn(@"%@ Running migration: %@", self.logTag, migration); + if ([OWSDatabaseMigration fetchObjectWithUniqueID:migration.uniqueId] == nil) { [migrationsToRun addObject:migration]; } } From 1d7e2e367e0451bd3930c2a02a980dab56cabf4a Mon Sep 17 00:00:00 2001 From: Michael Kirk Date: Fri, 2 Mar 2018 16:59:31 -0500 Subject: [PATCH 02/16] Fix migration to work with fallback notifications as well // FREEBIE --- SignalMessaging/environment/OWSSounds.m | 32 ++++++++++++++++--------- 1 file changed, 21 insertions(+), 11 deletions(-) diff --git a/SignalMessaging/environment/OWSSounds.m b/SignalMessaging/environment/OWSSounds.m index f1d3ea054..bf48527d9 100644 --- a/SignalMessaging/environment/OWSSounds.m +++ b/SignalMessaging/environment/OWSSounds.m @@ -244,6 +244,27 @@ NSString *const kOWSSoundsStorageGlobalNotificationKey = @"kOWSSoundsStorageGlob + (void)setGlobalNotificationSound:(OWSSound)sound { + [self.sharedManager setGlobalNotificationSound:sound]; +} + +- (void)setGlobalNotificationSound:(OWSSound)sound +{ + [self.dbConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *_Nonnull transaction) { + [self setGlobalNotificationSound:sound transaction:transaction]; + }]; +} + ++ (void)setGlobalNotificationSound:(OWSSound)sound transaction:(YapDatabaseReadWriteTransaction *)transaction +{ + [self.sharedManager setGlobalNotificationSound:sound transaction:transaction]; +} + +- (void)setGlobalNotificationSound:(OWSSound)sound transaction:(YapDatabaseReadWriteTransaction *)transaction +{ + OWSAssert(transaction); + + DDLogInfo(@"%@ Setting global notification sound to: %@", self.logTag, [[self class] displayNameForSound:sound]); + // Fallback push notifications play a sound specified by the server, but we don't want to store this configuration // on the server. Instead, we create a file with the same name as the default to be played when receiving // a fallback notification. @@ -274,17 +295,6 @@ NSString *const kOWSSoundsStorageGlobalNotificationKey = @"kOWSSoundsStorageGlob return; } - OWSSounds *instance = OWSSounds.sharedManager; - [instance.dbConnection setObject:@(sound) - forKey:kOWSSoundsStorageGlobalNotificationKey - inCollection:kOWSSoundsStorageNotificationCollection]; -} - -+ (void)setGlobalNotificationSound:(OWSSound)sound transaction:(YapDatabaseReadWriteTransaction *)transaction -{ - OWSAssert(transaction); - - DDLogInfo(@"%@ Setting global notification sound to: %s", sound); [transaction setObject:@(sound) forKey:kOWSSoundsStorageGlobalNotificationKey inCollection:kOWSSoundsStorageNotificationCollection]; From dfa082238e291f849a5e0f60dcc78450d8ac2492 Mon Sep 17 00:00:00 2001 From: Matthew Chen Date: Fri, 2 Mar 2018 16:01:08 -0500 Subject: [PATCH 03/16] Fix profile avatar downloads. --- SignalMessaging/profiles/OWSProfileManager.m | 30 +++++++++++++------- SignalMessaging/profiles/OWSUserProfile.h | 6 +++- SignalMessaging/profiles/OWSUserProfile.m | 24 +++++++++++++--- 3 files changed, 44 insertions(+), 16 deletions(-) diff --git a/SignalMessaging/profiles/OWSProfileManager.m b/SignalMessaging/profiles/OWSProfileManager.m index 90c280a52..47e91fcb4 100644 --- a/SignalMessaging/profiles/OWSProfileManager.m +++ b/SignalMessaging/profiles/OWSProfileManager.m @@ -785,12 +785,9 @@ const NSUInteger kOWSProfileManager_MaxAvatarDiameter = 640; return nil; } -- (void)downloadAvatarForUserProfile:(OWSUserProfile *)userProfileParameter +- (void)downloadAvatarForUserProfile:(OWSUserProfile *)userProfile { - OWSAssert(userProfileParameter); - - // Make a local copy. - OWSUserProfile *userProfile = [userProfileParameter copy]; + OWSAssert(userProfile); dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ if (userProfile.avatarUrlPath.length < 1) { @@ -915,14 +912,25 @@ const NSUInteger kOWSProfileManager_MaxAvatarDiameter = 640; return; } + // If we're transitioning from (no avatar -> no avatar) or from (same avatar -> same avatar), + // don't bother updating the avatar. + BOOL canSkipAvatarUpdate = ((avatarUrlPath.length == 0 && userProfile.avatarUrlPath.length == 0 + && userProfile.avatarFileName.length == 0) + || (avatarUrlPath.length > 0 && userProfile.avatarUrlPath.length > 0 && + [avatarUrlPath isEqualToString:userProfile.avatarUrlPath] && userProfile.avatarFileName)); + NSString *_Nullable profileName = [self decryptProfileNameData:profileNameEncrypted profileKey:userProfile.profileKey]; - [userProfile updateWithProfileName:profileName - avatarUrlPath:avatarUrlPath - avatarFileName:userProfile.avatarFileName // use existing file name if already downloaded - dbConnection:self.dbConnection - completion:nil]; + if (canSkipAvatarUpdate) { + [userProfile updateWithProfileName:profileName dbConnection:self.dbConnection completion:nil]; + } else { + [userProfile updateWithProfileName:profileName + avatarUrlPath:avatarUrlPath + avatarFileName:nil + dbConnection:self.dbConnection + completion:nil]; + } // If we're updating the profile that corresponds to our local number, // update the local profile as well. @@ -942,7 +950,7 @@ const NSUInteger kOWSProfileManager_MaxAvatarDiameter = 640; completion:nil]; } - if (userProfile.avatarUrlPath.length > 0 && userProfile.avatarFileName.length == 0) { + if (avatarUrlPath.length > 0) { [self downloadAvatarForUserProfile:userProfile]; } }); diff --git a/SignalMessaging/profiles/OWSUserProfile.h b/SignalMessaging/profiles/OWSUserProfile.h index c58e59e79..6499db695 100644 --- a/SignalMessaging/profiles/OWSUserProfile.h +++ b/SignalMessaging/profiles/OWSUserProfile.h @@ -1,5 +1,5 @@ // -// Copyright (c) 2017 Open Whisper Systems. All rights reserved. +// Copyright (c) 2018 Open Whisper Systems. All rights reserved. // #import @@ -41,6 +41,10 @@ extern NSString *const kLocalProfileUniqueId; #pragma mark - Update With... Methods +- (void)updateWithProfileName:(nullable NSString *)profileName + dbConnection:(YapDatabaseConnection *)dbConnection + completion:(nullable OWSUserProfileCompletion)completion; + - (void)updateWithProfileName:(nullable NSString *)profileName avatarUrlPath:(nullable NSString *)avatarUrlPath avatarFileName:(nullable NSString *)avatarFileName diff --git a/SignalMessaging/profiles/OWSUserProfile.m b/SignalMessaging/profiles/OWSUserProfile.m index 5bcf35de0..0b229a93b 100644 --- a/SignalMessaging/profiles/OWSUserProfile.m +++ b/SignalMessaging/profiles/OWSUserProfile.m @@ -115,6 +115,8 @@ NSString *const kLocalProfileUniqueId = @"kLocalProfileUniqueId"; didChange = [_avatarUrlPath isEqualToString:avatarUrlPath]; } + _avatarUrlPath = avatarUrlPath; + if (didChange) { // If the avatarURL changed, the avatarFileName can't be valid. // Clear it. @@ -137,8 +139,6 @@ NSString *const kLocalProfileUniqueId = @"kLocalProfileUniqueId"; dbConnection:(YapDatabaseConnection *)dbConnection completion:(nullable OWSUserProfileCompletion)completion { - NSDictionary *beforeSnapshot = self.dictionaryValue; - changeBlock(self); __block BOOL didChange = YES; @@ -146,12 +146,16 @@ NSString *const kLocalProfileUniqueId = @"kLocalProfileUniqueId"; NSString *collection = [[self class] collection]; OWSUserProfile *_Nullable latestInstance = [transaction objectForKey:self.uniqueId inCollection:collection]; if (latestInstance) { + NSDictionary *beforeSnapshot = latestInstance.dictionaryValue; + changeBlock(latestInstance); NSDictionary *afterSnapshot = latestInstance.dictionaryValue; if ([beforeSnapshot isEqual:afterSnapshot]) { - DDLogVerbose( - @"%@ Ignoring redundant update in %s: %@", self.logTag, functionName, self.debugDescription); + DDLogVerbose(@"%@ Ignoring redundant update in %s: %@", + self.logTag, + functionName, + self.debugDescription); didChange = NO; } else { [latestInstance saveWithTransaction:transaction]; @@ -200,6 +204,18 @@ NSString *const kLocalProfileUniqueId = @"kLocalProfileUniqueId"; }); } +- (void)updateWithProfileName:(nullable NSString *)profileName + dbConnection:(YapDatabaseConnection *)dbConnection + completion:(nullable OWSUserProfileCompletion)completion +{ + [self applyChanges:^(OWSUserProfile *userProfile) { + [userProfile setProfileName:[profileName ows_stripped]]; + } + functionName:__PRETTY_FUNCTION__ + dbConnection:dbConnection + completion:completion]; +} + - (void)updateWithProfileName:(nullable NSString *)profileName avatarUrlPath:(nullable NSString *)avatarUrlPath avatarFileName:(nullable NSString *)avatarFileName From 15921fa0b574646d5881dd9f9f13b0aa5a7cd928 Mon Sep 17 00:00:00 2001 From: Matthew Chen Date: Fri, 2 Mar 2018 16:24:33 -0500 Subject: [PATCH 04/16] Fix profile avatar downloads. --- SignalMessaging/profiles/OWSProfileManager.m | 20 ++++---------------- SignalMessaging/profiles/OWSUserProfile.h | 4 ---- SignalMessaging/profiles/OWSUserProfile.m | 14 +------------- 3 files changed, 5 insertions(+), 33 deletions(-) diff --git a/SignalMessaging/profiles/OWSProfileManager.m b/SignalMessaging/profiles/OWSProfileManager.m index 47e91fcb4..d2383ea5a 100644 --- a/SignalMessaging/profiles/OWSProfileManager.m +++ b/SignalMessaging/profiles/OWSProfileManager.m @@ -912,25 +912,13 @@ const NSUInteger kOWSProfileManager_MaxAvatarDiameter = 640; return; } - // If we're transitioning from (no avatar -> no avatar) or from (same avatar -> same avatar), - // don't bother updating the avatar. - BOOL canSkipAvatarUpdate = ((avatarUrlPath.length == 0 && userProfile.avatarUrlPath.length == 0 - && userProfile.avatarFileName.length == 0) - || (avatarUrlPath.length > 0 && userProfile.avatarUrlPath.length > 0 && - [avatarUrlPath isEqualToString:userProfile.avatarUrlPath] && userProfile.avatarFileName)); - NSString *_Nullable profileName = [self decryptProfileNameData:profileNameEncrypted profileKey:userProfile.profileKey]; - if (canSkipAvatarUpdate) { - [userProfile updateWithProfileName:profileName dbConnection:self.dbConnection completion:nil]; - } else { - [userProfile updateWithProfileName:profileName - avatarUrlPath:avatarUrlPath - avatarFileName:nil - dbConnection:self.dbConnection - completion:nil]; - } + [userProfile updateWithProfileName:profileName + avatarUrlPath:avatarUrlPath + dbConnection:self.dbConnection + completion:nil]; // If we're updating the profile that corresponds to our local number, // update the local profile as well. diff --git a/SignalMessaging/profiles/OWSUserProfile.h b/SignalMessaging/profiles/OWSUserProfile.h index 6499db695..35402fff1 100644 --- a/SignalMessaging/profiles/OWSUserProfile.h +++ b/SignalMessaging/profiles/OWSUserProfile.h @@ -41,10 +41,6 @@ extern NSString *const kLocalProfileUniqueId; #pragma mark - Update With... Methods -- (void)updateWithProfileName:(nullable NSString *)profileName - dbConnection:(YapDatabaseConnection *)dbConnection - completion:(nullable OWSUserProfileCompletion)completion; - - (void)updateWithProfileName:(nullable NSString *)profileName avatarUrlPath:(nullable NSString *)avatarUrlPath avatarFileName:(nullable NSString *)avatarFileName diff --git a/SignalMessaging/profiles/OWSUserProfile.m b/SignalMessaging/profiles/OWSUserProfile.m index 0b229a93b..4017f3a4f 100644 --- a/SignalMessaging/profiles/OWSUserProfile.m +++ b/SignalMessaging/profiles/OWSUserProfile.m @@ -109,7 +109,7 @@ NSString *const kLocalProfileUniqueId = @"kLocalProfileUniqueId"; BOOL didChange; if (_avatarUrlPath == nil && avatarUrlPath == nil) { didChange = NO; - } else if (_avatarUrlPath != nil && avatarUrlPath != nil) { + } else if (_avatarUrlPath != nil || avatarUrlPath != nil) { didChange = YES; } else { didChange = [_avatarUrlPath isEqualToString:avatarUrlPath]; @@ -204,18 +204,6 @@ NSString *const kLocalProfileUniqueId = @"kLocalProfileUniqueId"; }); } -- (void)updateWithProfileName:(nullable NSString *)profileName - dbConnection:(YapDatabaseConnection *)dbConnection - completion:(nullable OWSUserProfileCompletion)completion -{ - [self applyChanges:^(OWSUserProfile *userProfile) { - [userProfile setProfileName:[profileName ows_stripped]]; - } - functionName:__PRETTY_FUNCTION__ - dbConnection:dbConnection - completion:completion]; -} - - (void)updateWithProfileName:(nullable NSString *)profileName avatarUrlPath:(nullable NSString *)avatarUrlPath avatarFileName:(nullable NSString *)avatarFileName From b62a43217f3eadfee8d61f5571d2ee5cbd8f9947 Mon Sep 17 00:00:00 2001 From: Matthew Chen Date: Fri, 2 Mar 2018 16:31:44 -0500 Subject: [PATCH 05/16] Fix profile avatar downloads. --- SignalMessaging/profiles/OWSUserProfile.m | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/SignalMessaging/profiles/OWSUserProfile.m b/SignalMessaging/profiles/OWSUserProfile.m index 4017f3a4f..c0a55b95b 100644 --- a/SignalMessaging/profiles/OWSUserProfile.m +++ b/SignalMessaging/profiles/OWSUserProfile.m @@ -139,6 +139,10 @@ NSString *const kLocalProfileUniqueId = @"kLocalProfileUniqueId"; dbConnection:(YapDatabaseConnection *)dbConnection completion:(nullable OWSUserProfileCompletion)completion { + // self might be the latest instance, so take a "before" snapshot + // before any changes have been made. + __block NSDictionary *beforeSnapshot = [self.dictionaryValue copy]; + changeBlock(self); __block BOOL didChange = YES; @@ -146,11 +150,16 @@ NSString *const kLocalProfileUniqueId = @"kLocalProfileUniqueId"; NSString *collection = [[self class] collection]; OWSUserProfile *_Nullable latestInstance = [transaction objectForKey:self.uniqueId inCollection:collection]; if (latestInstance) { - NSDictionary *beforeSnapshot = latestInstance.dictionaryValue; + // If self is NOT the latest instance, take a new "before" snapshot + // before updating. + if (self != latestInstance) { + beforeSnapshot = [latestInstance.dictionaryValue copy]; + } changeBlock(latestInstance); - NSDictionary *afterSnapshot = latestInstance.dictionaryValue; + NSDictionary *afterSnapshot = [latestInstance.dictionaryValue copy]; + if ([beforeSnapshot isEqual:afterSnapshot]) { DDLogVerbose(@"%@ Ignoring redundant update in %s: %@", self.logTag, From 69c49d4a7bf08a0e3aba2c3eac4a79f3fa816590 Mon Sep 17 00:00:00 2001 From: Matthew Chen Date: Fri, 2 Mar 2018 16:33:38 -0500 Subject: [PATCH 06/16] Fix profile avatar downloads. --- SignalMessaging/profiles/OWSProfileManager.m | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/SignalMessaging/profiles/OWSProfileManager.m b/SignalMessaging/profiles/OWSProfileManager.m index d2383ea5a..024c8d14b 100644 --- a/SignalMessaging/profiles/OWSProfileManager.m +++ b/SignalMessaging/profiles/OWSProfileManager.m @@ -912,6 +912,13 @@ const NSUInteger kOWSProfileManager_MaxAvatarDiameter = 640; return; } + // If we're transitioning from (no avatar -> no avatar) or from (same avatar -> same avatar), + // don't bother updating the avatar. + BOOL canSkipAvatarUpdate = ((avatarUrlPath.length == 0 && userProfile.avatarUrlPath.length == 0 + && userProfile.avatarFileName.length == 0) + || (avatarUrlPath.length > 0 && userProfile.avatarUrlPath.length > 0 && + [avatarUrlPath isEqualToString:userProfile.avatarUrlPath] && userProfile.avatarFileName)); + NSString *_Nullable profileName = [self decryptProfileNameData:profileNameEncrypted profileKey:userProfile.profileKey]; @@ -938,7 +945,7 @@ const NSUInteger kOWSProfileManager_MaxAvatarDiameter = 640; completion:nil]; } - if (avatarUrlPath.length > 0) { + if (avatarUrlPath.length > 0 && !canSkipAvatarUpdate) { [self downloadAvatarForUserProfile:userProfile]; } }); From 5e02032fc36696e3d59a17e20619c1f004729714 Mon Sep 17 00:00:00 2001 From: Matthew Chen Date: Fri, 2 Mar 2018 16:38:46 -0500 Subject: [PATCH 07/16] Fix profile avatar downloads. --- SignalMessaging/profiles/OWSProfileManager.m | 2 ++ 1 file changed, 2 insertions(+) diff --git a/SignalMessaging/profiles/OWSProfileManager.m b/SignalMessaging/profiles/OWSProfileManager.m index 024c8d14b..4a53d34d1 100644 --- a/SignalMessaging/profiles/OWSProfileManager.m +++ b/SignalMessaging/profiles/OWSProfileManager.m @@ -814,6 +814,8 @@ const NSUInteger kOWSProfileManager_MaxAvatarDiameter = 640; [self.currentAvatarDownloads addObject:userProfile.recipientId]; } + DDLogVerbose(@"%@ downloading profile avatar: %@", self.logTag, userProfile.uniqueId); + NSString *tempDirectory = NSTemporaryDirectory(); NSString *tempFilePath = [tempDirectory stringByAppendingPathComponent:fileName]; From e89a0f815b0d4ba46458bb1aea15a126fc36e268 Mon Sep 17 00:00:00 2001 From: Matthew Chen Date: Fri, 2 Mar 2018 17:33:36 -0500 Subject: [PATCH 08/16] Respond to CR. --- SignalMessaging/profiles/OWSProfileManager.m | 18 +++++------------- 1 file changed, 5 insertions(+), 13 deletions(-) diff --git a/SignalMessaging/profiles/OWSProfileManager.m b/SignalMessaging/profiles/OWSProfileManager.m index 4a53d34d1..9bcedf4da 100644 --- a/SignalMessaging/profiles/OWSProfileManager.m +++ b/SignalMessaging/profiles/OWSProfileManager.m @@ -914,13 +914,6 @@ const NSUInteger kOWSProfileManager_MaxAvatarDiameter = 640; return; } - // If we're transitioning from (no avatar -> no avatar) or from (same avatar -> same avatar), - // don't bother updating the avatar. - BOOL canSkipAvatarUpdate = ((avatarUrlPath.length == 0 && userProfile.avatarUrlPath.length == 0 - && userProfile.avatarFileName.length == 0) - || (avatarUrlPath.length > 0 && userProfile.avatarUrlPath.length > 0 && - [avatarUrlPath isEqualToString:userProfile.avatarUrlPath] && userProfile.avatarFileName)); - NSString *_Nullable profileName = [self decryptProfileNameData:profileNameEncrypted profileKey:userProfile.profileKey]; @@ -936,18 +929,17 @@ const NSUInteger kOWSProfileManager_MaxAvatarDiameter = 640; OWSUserProfile *localUserProfile = self.localUserProfile; OWSAssert(localUserProfile); - // Don't clear avatarFileName optimistically. - // * The profile avatar probably isn't out of sync. - // * If the profile avatar is out of sync, it can be synced on next app launch. - // * We don't want to touch local avatar state until we've - // downloaded the latest avatar by downloadAvatarForUserProfile. [localUserProfile updateWithProfileName:profileName avatarUrlPath:avatarUrlPath dbConnection:self.dbConnection completion:nil]; } - if (avatarUrlPath.length > 0 && !canSkipAvatarUpdate) { + // Whenever we change avatarUrlPath, OWSUserProfile clears avatarFileName. + // So if avatarUrlPath is set and avatarFileName is not set, we should to + // download this avatar. downloadAvatarForUserProfile will de-bounce + // downloads. + if (userProfile.avatarUrlPath.length > 0 && userProfile.avatarFileName.length < 1) { [self downloadAvatarForUserProfile:userProfile]; } }); From 06d16bdec5bb9a42e4c0d0a27461f8ae4bc36657 Mon Sep 17 00:00:00 2001 From: Matthew Chen Date: Fri, 2 Mar 2018 09:04:55 -0500 Subject: [PATCH 09/16] Revert "Revert "Merge branch 'charlesmchen/debugLogs' into hotfix/2.20.1"" This reverts commit b1dd325ce8cb34dbb7ceb69e14587857a8e31c68. --- Signal/src/AppDelegate.m | 12 +- .../ViewControllers/DebugUI/DebugUIMessages.m | 1 - .../src/ViewControllers/DebugUI/DebugUIMisc.m | 1 - .../DebugUI/DebugUISyncMessages.m | 3 +- Signal/src/util/Pastelog.h | 15 +- Signal/src/util/Pastelog.m | 586 ++++++++++++------ .../translations/en.lproj/Localizable.strings | 19 +- SignalMessaging/profiles/OWSProfileManager.m | 1 - SignalMessaging/utils/DebugLogger.h | 6 +- SignalMessaging/utils/DebugLogger.m | 13 +- 10 files changed, 430 insertions(+), 227 deletions(-) diff --git a/Signal/src/AppDelegate.m b/Signal/src/AppDelegate.m index 4de216e56..254dc626d 100644 --- a/Signal/src/AppDelegate.m +++ b/Signal/src/AppDelegate.m @@ -46,6 +46,7 @@ #import #import #import +#import @import WebRTC; @import Intents; @@ -324,7 +325,7 @@ static NSString *const kURLHostVerifyPrefix = @"verify"; [controller addAction:[UIAlertAction actionWithTitle:NSLocalizedString(@"SETTINGS_ADVANCED_SUBMIT_DEBUGLOG", nil) style:UIAlertActionStyleDefault handler:^(UIAlertAction *_Nonnull action) { - [Pastelog submitLogsWithShareCompletion:^{ + [Pastelog submitLogsWithCompletion:^{ DDLogInfo( @"%@ exiting after sharing debug logs.", self.logTag); [DDLog flushLog]; @@ -396,6 +397,15 @@ static NSString *const kURLHostVerifyPrefix = @"verify"; if (languageCode.length > 0) { DDLogInfo(@"Language Code: %@", languageCode); } + + size_t size; + sysctlbyname("hw.machine", NULL, &size, NULL, 0); + char *machine = malloc(size); + sysctlbyname("hw.machine", machine, &size, NULL, 0); + NSString *platform = [NSString stringWithUTF8String:machine]; + free(machine); + + DDLogInfo(@"iPhone Version: %@", platform); } - (UIViewController *)loadingRootViewController diff --git a/Signal/src/ViewControllers/DebugUI/DebugUIMessages.m b/Signal/src/ViewControllers/DebugUI/DebugUIMessages.m index dde2caf40..53f33f172 100644 --- a/Signal/src/ViewControllers/DebugUI/DebugUIMessages.m +++ b/Signal/src/ViewControllers/DebugUI/DebugUIMessages.m @@ -7,7 +7,6 @@ #import "OWSTableViewController.h" #import "Signal-Swift.h" #import "ThreadUtil.h" -#import #import #import #import diff --git a/Signal/src/ViewControllers/DebugUI/DebugUIMisc.m b/Signal/src/ViewControllers/DebugUI/DebugUIMisc.m index 41ecfa7e9..40eb0cce6 100644 --- a/Signal/src/ViewControllers/DebugUI/DebugUIMisc.m +++ b/Signal/src/ViewControllers/DebugUI/DebugUIMisc.m @@ -10,7 +10,6 @@ #import "RegistrationViewController.h" #import "Signal-Swift.h" #import "ThreadUtil.h" -#import #import #import #import diff --git a/Signal/src/ViewControllers/DebugUI/DebugUISyncMessages.m b/Signal/src/ViewControllers/DebugUI/DebugUISyncMessages.m index 51cb890db..dd033379a 100644 --- a/Signal/src/ViewControllers/DebugUI/DebugUISyncMessages.m +++ b/Signal/src/ViewControllers/DebugUI/DebugUISyncMessages.m @@ -1,5 +1,5 @@ // -// Copyright (c) 2017 Open Whisper Systems. All rights reserved. +// Copyright (c) 2018 Open Whisper Systems. All rights reserved. // #import "DebugUISyncMessages.h" @@ -7,7 +7,6 @@ #import "OWSTableViewController.h" #import "Signal-Swift.h" #import "ThreadUtil.h" -#import #import #import #import diff --git a/Signal/src/util/Pastelog.h b/Signal/src/util/Pastelog.h index 99356aa0e..0d46da066 100644 --- a/Signal/src/util/Pastelog.h +++ b/Signal/src/util/Pastelog.h @@ -2,14 +2,17 @@ // Copyright (c) 2018 Open Whisper Systems. All rights reserved. // +NS_ASSUME_NONNULL_BEGIN + +typedef void (^SubmitDebugLogsCompletion)(void); + @interface Pastelog : NSObject -typedef void (^DebugLogsUploadedBlock)(NSError *error, NSString *urlString); -typedef void (^DebugLogsSharedBlock)(void); +- (instancetype)init NS_UNAVAILABLE; -+(void)submitLogs; -+ (void)submitLogsWithShareCompletion:(nullable DebugLogsSharedBlock)block; -+ (void)submitLogsWithUploadCompletion:(DebugLogsUploadedBlock)block; -+ (void)submitLogsWithUploadCompletion:(DebugLogsUploadedBlock)block forFileLogger:(DDFileLogger *)fileLogger; ++ (void)submitLogs; ++ (void)submitLogsWithCompletion:(nullable SubmitDebugLogsCompletion)completion; @end + +NS_ASSUME_NONNULL_END diff --git a/Signal/src/util/Pastelog.m b/Signal/src/util/Pastelog.m index d6dc5b7cb..f0d6fd907 100644 --- a/Signal/src/util/Pastelog.m +++ b/Signal/src/util/Pastelog.m @@ -5,6 +5,7 @@ #import "Pastelog.h" #import "Signal-Swift.h" #import "ThreadUtil.h" +#import #import #import #import @@ -12,13 +13,199 @@ #import #import #import -#import -@interface Pastelog () +NS_ASSUME_NONNULL_BEGIN + +typedef void (^UploadDebugLogsSuccess)(NSURL *url); +typedef void (^UploadDebugLogsFailure)(NSString *localizedErrorMessage); + +#pragma mark - + +@class DebugLogUploader; + +typedef void (^DebugLogUploadSuccess)(DebugLogUploader *uploader, NSURL *url); +typedef void (^DebugLogUploadFailure)(DebugLogUploader *uploader, NSError *error); + +@interface DebugLogUploader : NSObject + +@property (nonatomic) NSMutableData *responseData; +@property (nonatomic, nullable) DebugLogUploadSuccess success; +@property (nonatomic, nullable) DebugLogUploadFailure failure; + +@end + +#pragma mark - + +@implementation DebugLogUploader + +- (void)dealloc +{ + DDLogVerbose(@"Dealloc: %@", self.logTag); +} + +- (void)uploadFileWithURL:(NSURL *)fileUrl success:(DebugLogUploadSuccess)success failure:(DebugLogUploadFailure)failure +{ + OWSAssert(fileUrl); + OWSAssert(success); + OWSAssert(failure); + + self.success = success; + self.failure = failure; + self.responseData = [NSMutableData new]; + + NSURL *url = [NSURL URLWithString:@"https://filebin.net"]; + + NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:url + cachePolicy:NSURLRequestReloadIgnoringLocalCacheData + timeoutInterval:30]; + [request setHTTPMethod:@"POST"]; + [request addValue:fileUrl.lastPathComponent forHTTPHeaderField:@"filename"]; + [request addValue:@"application/zip" forHTTPHeaderField:@"Content-Type"]; + NSData *_Nullable data = [NSData dataWithContentsOfURL:fileUrl]; + if (!data) { + [self failWithError:[NSError errorWithDomain:@"PastelogKit" + code:10002 + userInfo:@{ NSLocalizedDescriptionKey : @"Could not load data." }]]; + return; + } + // TODO: + [request setHTTPBody:data]; + + NSURLConnection *connection = [NSURLConnection connectionWithRequest:request delegate:self]; + [connection start]; +} + +#pragma mark - Delegate Methods + +- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data +{ + DDLogVerbose(@"%@ %s", self.logTag, __PRETTY_FUNCTION__); + + [self.responseData appendData:data]; +} + +- (void)connectionDidFinishLoading:(NSURLConnection *)connection +{ + DDLogVerbose(@"%@ %s", self.logTag, __PRETTY_FUNCTION__); + + NSError *error; + NSDictionary *_Nullable dict = [NSJSONSerialization JSONObjectWithData:self.responseData options:0 error:&error]; + if (error) { + DDLogError(@"%@ response length: %zd", self.logTag, self.responseData.length); + [self failWithError:error]; + return; + } + + if (![dict isKindOfClass:[NSDictionary class]]) { + DDLogError(@"%@ response (1): %@", self.logTag, dict); + [self failWithError:[NSError errorWithDomain:@"PastelogKit" + code:10003 + userInfo:@{ NSLocalizedDescriptionKey : @"Malformed response (root)." }]]; + return; + } + + NSArray *_Nullable links = [dict objectForKey:@"links"]; + if (![links isKindOfClass:[NSArray class]]) { + DDLogError(@"%@ response (2): %@", self.logTag, dict); + [self failWithError:[NSError errorWithDomain:@"PastelogKit" + code:10004 + userInfo:@{ NSLocalizedDescriptionKey : @"Malformed response (links)." }]]; + return; + } + NSString *_Nullable urlString = nil; + for (NSDictionary *linkMap in links) { + if (![linkMap isKindOfClass:[NSDictionary class]]) { + DDLogError(@"%@ response (2): %@", self.logTag, dict); + [self failWithError:[NSError + errorWithDomain:@"PastelogKit" + code:10005 + userInfo:@{ NSLocalizedDescriptionKey : @"Malformed response (linkMap)." }]]; + return; + } + NSString *_Nullable linkRel = [linkMap objectForKey:@"rel"]; + if (![linkRel isKindOfClass:[NSString class]]) { + DDLogError(@"%@ response (linkRel): %@", self.logTag, dict); + continue; + } + if (![linkRel isEqualToString:@"file"]) { + DDLogError(@"%@ response (linkRel value): %@", self.logTag, dict); + continue; + } + NSString *_Nullable linkHref = [linkMap objectForKey:@"href"]; + if (![linkHref isKindOfClass:[NSString class]]) { + DDLogError(@"%@ response (linkHref): %@", self.logTag, dict); + continue; + } + urlString = linkHref; + break; + } + [self succeedWithUrl:[NSURL URLWithString:urlString]]; +} + +- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response +{ + NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)response; + + NSInteger statusCode = httpResponse.statusCode; + // We'll accept any 2xx status code. + NSInteger statusCodeClass = statusCode - (statusCode % 100); + if (statusCodeClass != 200) { + DDLogError(@"%@ statusCode: %zd, %zd", self.logTag, statusCode, statusCodeClass); + DDLogError(@"%@ headers: %@", self.logTag, httpResponse.allHeaderFields); + [self failWithError:[NSError errorWithDomain:@"PastelogKit" + code:10001 + userInfo:@{ NSLocalizedDescriptionKey : @"Invalid response code." }]]; + } +} + +- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error +{ + DDLogVerbose(@"%@ %s", self.logTag, __PRETTY_FUNCTION__); + + [self failWithError:error]; +} + +- (void)failWithError:(NSError *)error +{ + OWSAssert(error); + + DDLogError(@"%@ %s %@", self.logTag, __PRETTY_FUNCTION__, error); + + DispatchMainThreadSafe(^{ + // Call the completions exactly once. + if (self.failure) { + self.failure(self, error); + } + self.success = nil; + self.failure = nil; + }); +} + +- (void)succeedWithUrl:(NSURL *)url +{ + OWSAssert(url); + + DDLogVerbose(@"%@ %s %@", self.logTag, __PRETTY_FUNCTION__, url); + + DispatchMainThreadSafe(^{ + // Call the completions exactly once. + if (self.success) { + self.success(self, url); + } + self.success = nil; + self.failure = nil; + }); +} + +@end + +#pragma mark - + +@interface Pastelog () @property (nonatomic) UIAlertController *loadingAlert; -@property (nonatomic) NSMutableData *responseData; -@property (nonatomic) DebugLogsUploadedBlock block; + +@property (nonatomic) DebugLogUploader *currentUploader; @end @@ -26,237 +213,226 @@ @implementation Pastelog -+(void)submitLogs { - [self submitLogsWithShareCompletion:nil]; -} - -+ (void)submitLogsWithShareCompletion:(nullable DebugLogsSharedBlock)shareCompletionParam ++ (instancetype)sharedManager { - DebugLogsSharedBlock shareCompletion = ^{ - if (shareCompletionParam) { - // Wait a moment. If PasteLog opens a URL, it needs a moment to complete. - dispatch_after( - dispatch_time(DISPATCH_TIME_NOW, 2 * NSEC_PER_SEC), dispatch_get_main_queue(), shareCompletionParam); - } - }; - - [self submitLogsWithUploadCompletion:^(NSError *error, NSString *urlString) { - if (!error) { - UIAlertController *alert = [UIAlertController - alertControllerWithTitle:NSLocalizedString(@"DEBUG_LOG_ALERT_TITLE", @"Title of the debug log alert.") - message:NSLocalizedString( - @"DEBUG_LOG_ALERT_MESSAGE", @"Message of the debug log alert.") - preferredStyle:UIAlertControllerStyleAlert]; - [alert - addAction:[UIAlertAction - actionWithTitle:NSLocalizedString(@"DEBUG_LOG_ALERT_OPTION_EMAIL", - @"Label for the 'email debug log' option of the the debug log alert.") - style:UIAlertActionStyleDefault - handler:^(UIAlertAction *_Nonnull action) { - [Pastelog.sharedManager submitEmail:urlString]; - - shareCompletion(); - }]]; - [alert addAction:[UIAlertAction - actionWithTitle:NSLocalizedString(@"DEBUG_LOG_ALERT_OPTION_COPY_LINK", - @"Label for the 'copy link' option of the the debug log alert.") - style:UIAlertActionStyleDefault - handler:^(UIAlertAction *_Nonnull action) { - UIPasteboard *pb = [UIPasteboard generalPasteboard]; - [pb setString:urlString]; - - shareCompletion(); - }]]; -#ifdef DEBUG - [alert addAction:[UIAlertAction - actionWithTitle:NSLocalizedString(@"DEBUG_LOG_ALERT_OPTION_SEND_TO_SELF", - @"Label for the 'send to self' option of the the debug log alert.") - style:UIAlertActionStyleDefault - handler:^(UIAlertAction *_Nonnull action) { - [Pastelog.sharedManager sendToSelf:urlString]; - }]]; - [alert addAction:[UIAlertAction - actionWithTitle: - NSLocalizedString(@"DEBUG_LOG_ALERT_OPTION_SEND_TO_LAST_THREAD", - @"Label for the 'send to last thread' option of the the debug log alert.") - style:UIAlertActionStyleDefault - handler:^(UIAlertAction *_Nonnull action) { - [Pastelog.sharedManager sendToMostRecentThread:urlString]; - }]]; -#endif - [alert addAction: - [UIAlertAction - actionWithTitle:NSLocalizedString(@"DEBUG_LOG_ALERT_OPTION_BUG_REPORT", - @"Label for the 'Open a Bug Report' option of the the debug log alert.") - style:UIAlertActionStyleCancel - handler:^(UIAlertAction *_Nonnull action) { - [Pastelog.sharedManager prepareRedirection:urlString - shareCompletion:shareCompletion]; - }]]; - UIViewController *presentingViewController - = UIApplication.sharedApplication.frontmostViewControllerIgnoringAlerts; - [presentingViewController presentViewController:alert animated:NO completion:nil]; - } else{ - UIAlertView *alertView = - [[UIAlertView alloc] initWithTitle:NSLocalizedString(@"DEBUG_LOG_FAILURE_ALERT_TITLE", - @"Title of the alert indicating the debug log upload failed.") - message:error.localizedDescription - delegate:nil - cancelButtonTitle:@"OK" - otherButtonTitles:nil, nil]; - [alertView show]; - } - }]; -} - -+ (void)submitLogsWithUploadCompletion:(DebugLogsUploadedBlock)block -{ - [self submitLogsWithUploadCompletion:block forFileLogger:[[DDFileLogger alloc] init]]; -} - -+ (void)submitLogsWithUploadCompletion:(DebugLogsUploadedBlock)block forFileLogger:(DDFileLogger *)fileLogger -{ - - [self sharedManager].block = block; - - [self sharedManager].loadingAlert = - [UIAlertController alertControllerWithTitle:NSLocalizedString(@"DEBUG_LOG_ACTIVITY_INDICATOR", - @"Message indicating that the debug log is being uploaded.") - message:nil - preferredStyle:UIAlertControllerStyleAlert]; - UIViewController *presentingViewController = UIApplication.sharedApplication.frontmostViewControllerIgnoringAlerts; - [presentingViewController presentViewController:[self sharedManager].loadingAlert animated:NO completion:nil]; - - NSArray *logFilePaths = DebugLogger.sharedLogger.allLogFilePaths; - - NSMutableDictionary *gistFiles = [NSMutableDictionary new]; - - for (NSString *logFilePath in logFilePaths) { - NSError *error; - NSString *logContents = - [NSString stringWithContentsOfFile:logFilePath encoding:NSUTF8StringEncoding error:&error]; - if (error) { - OWSFail(@"%@ Error loading log file contents: %@", self.logTag, error); - continue; - } - gistFiles[logFilePath.lastPathComponent] = @{ - @"content" : logContents, - }; - } - - NSDictionary *gistDict = @{@"description":[self gistDescription], @"files":gistFiles}; - - NSData *postData = [NSJSONSerialization dataWithJSONObject:gistDict options:0 error:nil]; - - NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:[[NSURL alloc] initWithString:@"https://api.github.com/gists"] cachePolicy:NSURLRequestReloadIgnoringLocalCacheData timeoutInterval:30]; - - [[self sharedManager] setResponseData:[NSMutableData data]]; - [[self sharedManager] setBlock:block]; - - [request setHTTPMethod:@"POST"]; - [request setHTTPBody:postData]; - - NSURLConnection *connection = [NSURLConnection connectionWithRequest:request delegate:[self sharedManager]]; - - [connection start]; - -} - -+(Pastelog*)sharedManager { static Pastelog *sharedMyManager = nil; static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ - sharedMyManager = [[self alloc] init]; + sharedMyManager = [[self alloc] initDefault]; }); return sharedMyManager; } --(instancetype)init { - if (self = [super init]) { - self.responseData = [NSMutableData data]; +- (instancetype)initDefault +{ + self = [super init]; - OWSSingletonAssert(); + if (!self) { + return self; } + + OWSSingletonAssert(); + return self; } -+(NSString*)gistDescription{ - size_t size; - sysctlbyname("hw.machine", NULL, &size, NULL, 0); - char *machine = malloc(size); - sysctlbyname("hw.machine", machine, &size, NULL, 0); - NSString *platform = [NSString stringWithUTF8String:machine]; - free(machine); - - NSString *gistDesc = [NSString stringWithFormat:@"iPhone Version: %@, iOS Version: %@", platform,[UIDevice currentDevice].systemVersion]; - - return gistDesc; ++ (void)submitLogs +{ + [self submitLogsWithCompletion:nil]; } -#pragma mark Network delegates ++ (void)submitLogsWithCompletion:(nullable SubmitDebugLogsCompletion)completionParam +{ + SubmitDebugLogsCompletion completion = ^{ + if (completionParam) { + // Wait a moment. If PasteLog opens a URL, it needs a moment to complete. + dispatch_after( + dispatch_time(DISPATCH_TIME_NOW, 2 * NSEC_PER_SEC), dispatch_get_main_queue(), completionParam); + } + }; --(void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data{ - [self.responseData appendData:data]; + [self uploadLogsWithSuccess:^(NSURL *url) { + UIAlertController *alert = [UIAlertController + alertControllerWithTitle:NSLocalizedString(@"DEBUG_LOG_ALERT_TITLE", @"Title of the debug log alert.") + message:NSLocalizedString(@"DEBUG_LOG_ALERT_MESSAGE", @"Message of the debug log alert.") + preferredStyle:UIAlertControllerStyleAlert]; + [alert addAction:[UIAlertAction + actionWithTitle:NSLocalizedString(@"DEBUG_LOG_ALERT_OPTION_EMAIL", + @"Label for the 'email debug log' option of the the debug log alert.") + style:UIAlertActionStyleDefault + handler:^(UIAlertAction *_Nonnull action) { + [Pastelog.sharedManager submitEmail:url]; + + completion(); + }]]; + [alert addAction:[UIAlertAction + actionWithTitle:NSLocalizedString(@"DEBUG_LOG_ALERT_OPTION_COPY_LINK", + @"Label for the 'copy link' option of the the debug log alert.") + style:UIAlertActionStyleDefault + handler:^(UIAlertAction *_Nonnull action) { + UIPasteboard *pb = [UIPasteboard generalPasteboard]; + [pb setString:url.absoluteString]; + + completion(); + }]]; +#ifdef DEBUG + [alert addAction:[UIAlertAction + actionWithTitle:NSLocalizedString(@"DEBUG_LOG_ALERT_OPTION_SEND_TO_SELF", + @"Label for the 'send to self' option of the the debug log alert.") + style:UIAlertActionStyleDefault + handler:^(UIAlertAction *_Nonnull action) { + [Pastelog.sharedManager sendToSelf:url]; + }]]; + [alert + addAction:[UIAlertAction + actionWithTitle:NSLocalizedString(@"DEBUG_LOG_ALERT_OPTION_SEND_TO_LAST_THREAD", + @"Label for the 'send to last thread' option of the the debug log alert.") + style:UIAlertActionStyleDefault + handler:^(UIAlertAction *_Nonnull action) { + [Pastelog.sharedManager sendToMostRecentThread:url]; + }]]; +#endif + [alert + addAction:[UIAlertAction + actionWithTitle:NSLocalizedString(@"DEBUG_LOG_ALERT_OPTION_BUG_REPORT", + @"Label for the 'Open a Bug Report' option of the the debug log alert.") + style:UIAlertActionStyleCancel + handler:^(UIAlertAction *_Nonnull action) { + [Pastelog.sharedManager prepareRedirection:url completion:completion]; + }]]; + UIViewController *presentingViewController + = UIApplication.sharedApplication.frontmostViewControllerIgnoringAlerts; + [presentingViewController presentViewController:alert animated:NO completion:nil]; + }]; } -- (void)connectionDidFinishLoading:(NSURLConnection *)connection { - [self.loadingAlert - dismissViewControllerAnimated:NO - completion:^{ - NSError *error; - NSDictionary *dict = - [NSJSONSerialization JSONObjectWithData:self.responseData options:0 error:&error]; - if (!error) { - self.block(nil, [dict objectForKey:@"html_url"]); - } else { - DDLogError(@"Error on debug response: %@", error); - self.block(error, nil); - } - }]; - self.loadingAlert = nil; ++ (void)uploadLogsWithSuccess:(nullable UploadDebugLogsSuccess)success +{ + OWSAssert(success); + + [[self sharedManager] uploadLogsWithSuccess:success + failure:^(NSString *localizedErrorMessage) { + [Pastelog showFailureAlertWithMessage:localizedErrorMessage]; + }]; } -- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response { +- (void)uploadLogsWithSuccess:(nullable UploadDebugLogsSuccess)successParam failure:(UploadDebugLogsFailure)failureParam +{ + OWSAssert(successParam); + OWSAssert(failureParam); - NSHTTPURLResponse* httpResponse = (NSHTTPURLResponse*)response; + // Ensure that we call the completions on the main thread. + UploadDebugLogsSuccess success = ^(NSURL *url) { + if (successParam) { + DispatchMainThreadSafe(^{ + successParam(url); + }); + } + }; + UploadDebugLogsFailure failure = ^(NSString *localizedErrorMessage) { + DispatchMainThreadSafe(^{ + failureParam(localizedErrorMessage); + }); + }; - if ( [httpResponse statusCode] != 201) { - DDLogError(@"Failed to submit debug log: %@", httpResponse.debugDescription); - [self.loadingAlert - dismissViewControllerAnimated:NO - completion:^{ - [connection cancel]; - self.block([NSError errorWithDomain:@"PastelogKit" code:10001 userInfo:@{}], nil); - }]; - self.loadingAlert = nil; + // Phase 1. Make a local copy of all of the log files. + NSDateFormatter *dateFormatter = [NSDateFormatter new]; + [dateFormatter setLocale:[NSLocale currentLocale]]; + [dateFormatter setDateFormat:@"yyyy.MM.dd hh.mm.ss"]; + NSString *dateString = [dateFormatter stringFromDate:[NSDate new]]; + NSString *logsName = [[dateString stringByAppendingString:@" "] stringByAppendingString:NSUUID.UUID.UUIDString]; + NSString *tempDirectory = NSTemporaryDirectory(); + NSString *zipFilePath = + [tempDirectory stringByAppendingPathComponent:[logsName stringByAppendingPathExtension:@"zip"]]; + NSString *zipDirPath = [tempDirectory stringByAppendingPathComponent:logsName]; + [OWSFileSystem ensureDirectoryExists:zipDirPath]; + [OWSFileSystem protectFileOrFolderAtPath:zipDirPath]; + + NSArray *logFilePaths = DebugLogger.sharedLogger.allLogFilePaths; + if (logFilePaths.count < 1) { + failure(NSLocalizedString(@"DEBUG_LOG_ALERT_NO_LOGS", @"Error indicating that no debug logs could be found.")); + return; } + + for (NSString *logFilePath in logFilePaths) { + NSString *copyFilePath = [zipDirPath stringByAppendingPathComponent:logFilePath.lastPathComponent]; + NSError *error; + [[NSFileManager defaultManager] copyItemAtPath:logFilePath toPath:copyFilePath error:&error]; + if (error) { + failure(NSLocalizedString( + @"DEBUG_LOG_ALERT_COULD_NOT_COPY_LOGS", @"Error indicating that the debug logs could not be copied.")); + return; + } + [OWSFileSystem protectFileOrFolderAtPath:copyFilePath]; + } + + // Phase 2. Zip up the log files. + BOOL zipSuccess = + [SSZipArchive createZipFileAtPath:zipFilePath withContentsOfDirectory:zipDirPath withPassword:nil]; + if (!zipSuccess) { + failure(NSLocalizedString( + @"DEBUG_LOG_ALERT_COULD_NOT_PACKAGE_LOGS", @"Error indicating that the debug logs could not be packaged.")); + return; + } + + [OWSFileSystem protectFileOrFolderAtPath:zipFilePath]; + [OWSFileSystem deleteFile:zipDirPath]; + + // Phase 3. Upload the log files. + + __weak Pastelog *weakSelf = self; + self.currentUploader = [DebugLogUploader new]; + [self.currentUploader uploadFileWithURL:[NSURL fileURLWithPath:zipFilePath] + success:^(DebugLogUploader *uploader, NSURL *url) { + if (uploader != weakSelf.currentUploader) { + // Ignore events from obsolete uploaders. + return; + } + [OWSFileSystem deleteFile:zipFilePath]; + success(url); + } + failure:^(DebugLogUploader *uploader, NSError *error) { + if (uploader != weakSelf.currentUploader) { + // Ignore events from obsolete uploaders. + return; + } + [OWSFileSystem deleteFile:zipFilePath]; + failure(NSLocalizedString( + @"DEBUG_LOG_ALERT_ERROR_UPLOADING_LOG", @"Error indicating that a debug log could not be uploaded.")); + }]; } -- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error { - [self.loadingAlert dismissViewControllerAnimated:NO - completion:^{ - DDLogError(@"Uploading logs failed with error: %@", error); - self.block(error, nil); - }]; - self.loadingAlert = nil; ++ (void)showFailureAlertWithMessage:(NSString *)message +{ + UIAlertController *alert = [UIAlertController + alertControllerWithTitle:NSLocalizedString(@"DEBUG_LOG_ALERT_TITLE", + @"Title of the alert shown for failures while uploading debug logs.") + message:message + preferredStyle:UIAlertControllerStyleAlert]; + [alert addAction:[UIAlertAction actionWithTitle:NSLocalizedString(@"OK", @"") + style:UIAlertActionStyleDefault + handler:nil]]; + UIViewController *presentingViewController = UIApplication.sharedApplication.frontmostViewControllerIgnoringAlerts; + [presentingViewController presentViewController:alert animated:NO completion:nil]; } #pragma mark Logs submission -- (void)submitEmail:(NSString*)url { +- (void)submitEmail:(NSURL *)url +{ NSString *emailAddress = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"LOGS_EMAIL"]; NSString *urlString = [NSString stringWithString: [[NSString stringWithFormat:@"mailto:%@?subject=iOS%%20Debug%%20Log&body=", emailAddress] stringByAppendingString:[[NSString stringWithFormat:@"Log URL: %@ \n Tell us about the issue: ", url]stringByAddingPercentEscapesUsingEncoding:NSASCIIStringEncoding]]]; - [UIApplication.sharedApplication openURL: [NSURL URLWithString: urlString]]; + [UIApplication.sharedApplication openURL:[NSURL URLWithString:urlString]]; } -- (void)prepareRedirection:(NSString *)url shareCompletion:(DebugLogsSharedBlock)shareCompletion +- (void)prepareRedirection:(NSURL *)url completion:(SubmitDebugLogsCompletion)completion { - OWSAssert(shareCompletion); + OWSAssert(completion); UIPasteboard *pb = [UIPasteboard generalPasteboard]; - [pb setString:url]; + [pb setString:url.absoluteString]; UIAlertController *alert = [UIAlertController alertControllerWithTitle:NSLocalizedString(@"DEBUG_LOG_GITHUB_ISSUE_ALERT_TITLE", @@ -272,13 +448,13 @@ openURL:[NSURL URLWithString:[[NSBundle mainBundle] objectForInfoDictionaryKey:@"LOGS_URL"]]]; - shareCompletion(); + completion(); }]]; UIViewController *presentingViewController = UIApplication.sharedApplication.frontmostViewControllerIgnoringAlerts; [presentingViewController presentViewController:alert animated:NO completion:nil]; } -- (void)sendToSelf:(NSString *)url +- (void)sendToSelf:(NSURL *)url { if (![TSAccountManager isRegistered]) { return; @@ -292,14 +468,14 @@ readWriteWithBlock:^(YapDatabaseReadWriteTransaction *_Nonnull transaction) { thread = [TSContactThread getOrCreateThreadWithContactId:recipientId transaction:transaction]; }]; - [ThreadUtil sendMessageWithText:url inThread:thread messageSender:messageSender]; + [ThreadUtil sendMessageWithText:url.absoluteString inThread:thread messageSender:messageSender]; }); // Also copy to pasteboard. - [[UIPasteboard generalPasteboard] setString:url]; + [[UIPasteboard generalPasteboard] setString:url.absoluteString]; } -- (void)sendToMostRecentThread:(NSString *)url +- (void)sendToMostRecentThread:(NSURL *)url { if (![TSAccountManager isRegistered]) { return; @@ -312,11 +488,13 @@ readWriteWithBlock:^(YapDatabaseReadWriteTransaction *_Nonnull transaction) { thread = [[transaction ext:TSThreadDatabaseViewExtensionName] firstObjectInGroup:[TSThread collection]]; }]; - [ThreadUtil sendMessageWithText:url inThread:thread messageSender:messageSender]; + [ThreadUtil sendMessageWithText:url.absoluteString inThread:thread messageSender:messageSender]; }); // Also copy to pasteboard. - [[UIPasteboard generalPasteboard] setString:url]; + [[UIPasteboard generalPasteboard] setString:url.absoluteString]; } @end + +NS_ASSUME_NONNULL_END diff --git a/Signal/translations/en.lproj/Localizable.strings b/Signal/translations/en.lproj/Localizable.strings index c68e554da..9a973d039 100644 --- a/Signal/translations/en.lproj/Localizable.strings +++ b/Signal/translations/en.lproj/Localizable.strings @@ -499,12 +499,21 @@ /* The day before today. */ "DATE_YESTERDAY" = "Yesterday"; -/* Message indicating that the debug log is being uploaded. */ -"DEBUG_LOG_ACTIVITY_INDICATOR" = "Sending Debug Log..."; +/* Error indicating that the debug logs could not be copied. */ +"DEBUG_LOG_ALERT_COULD_NOT_COPY_LOGS" = "Could not copy logs."; + +/* Error indicating that the debug logs could not be packaged. */ +"DEBUG_LOG_ALERT_COULD_NOT_PACKAGE_LOGS" = "Could not package logs."; + +/* Error indicating that a debug log could not be uploaded. */ +"DEBUG_LOG_ALERT_ERROR_UPLOADING_LOG" = "Could not upload logs."; /* Message of the debug log alert. */ "DEBUG_LOG_ALERT_MESSAGE" = "What would you like to do with the link to your debug log?"; +/* Error indicating that no debug logs could be found. */ +"DEBUG_LOG_ALERT_NO_LOGS" = "Could not find any logs."; + /* Label for the 'Open a Bug Report' option of the the debug log alert. */ "DEBUG_LOG_ALERT_OPTION_BUG_REPORT" = "Open a Bug Report"; @@ -520,12 +529,10 @@ /* Label for the 'send to self' option of the the debug log alert. */ "DEBUG_LOG_ALERT_OPTION_SEND_TO_SELF" = "Send to Self"; -/* Title of the debug log alert. */ +/* Title of the alert shown for failures while uploading debug logs. + Title of the debug log alert. */ "DEBUG_LOG_ALERT_TITLE" = "One More Step"; -/* Title of the alert indicating the debug log upload failed. */ -"DEBUG_LOG_FAILURE_ALERT_TITLE" = "Failed to Submit Debug Log"; - /* Message of the alert before redirecting to Github Issues. */ "DEBUG_LOG_GITHUB_ISSUE_ALERT_MESSAGE" = "The gist link was copied in your clipboard. You are about to be redirected to the GitHub issue list."; diff --git a/SignalMessaging/profiles/OWSProfileManager.m b/SignalMessaging/profiles/OWSProfileManager.m index 9bcedf4da..d4476b9fc 100644 --- a/SignalMessaging/profiles/OWSProfileManager.m +++ b/SignalMessaging/profiles/OWSProfileManager.m @@ -7,7 +7,6 @@ #import "NSString+OWS.h" #import "OWSUserProfile.h" #import "UIImage+OWS.h" -#import #import #import #import diff --git a/SignalMessaging/utils/DebugLogger.h b/SignalMessaging/utils/DebugLogger.h index a3ec93bfb..a08037e98 100644 --- a/SignalMessaging/utils/DebugLogger.h +++ b/SignalMessaging/utils/DebugLogger.h @@ -1,9 +1,11 @@ // -// Copyright (c) 2017 Open Whisper Systems. All rights reserved. +// Copyright (c) 2018 Open Whisper Systems. All rights reserved. // #import +NS_ASSUME_NONNULL_BEGIN + @interface DebugLogger : NSObject + (instancetype)sharedLogger; @@ -19,3 +21,5 @@ - (NSArray *)allLogFilePaths; @end + +NS_ASSUME_NONNULL_END diff --git a/SignalMessaging/utils/DebugLogger.m b/SignalMessaging/utils/DebugLogger.m index cb38f4f8f..bb306982f 100644 --- a/SignalMessaging/utils/DebugLogger.m +++ b/SignalMessaging/utils/DebugLogger.m @@ -11,9 +11,13 @@ #pragma mark Logging - Production logging wants us to write some logs to a file in case we need it for debugging. #import +NS_ASSUME_NONNULL_BEGIN + +const NSUInteger kMaxDebugLogFileSize = 1024 * 1024 * 3; + @interface DebugLogger () -@property (nonatomic) DDFileLogger *fileLogger; +@property (nonatomic, nullable) DDFileLogger *fileLogger; @end @@ -66,9 +70,8 @@ // 24 hour rolling. self.fileLogger.rollingFrequency = kDayInterval; // Keep last 3 days of logs - or last 3 logs (if logs rollover due to max file size). - self.fileLogger.logFileManager.maximumNumberOfLogFiles = 3; - // Raise the max file size per log file to 3 MB. - self.fileLogger.maximumFileSize = 1024 * 1024 * 3; + self.fileLogger.logFileManager.maximumNumberOfLogFiles = 24; + self.fileLogger.maximumFileSize = kMaxDebugLogFileSize; self.fileLogger.logFormatter = [OWSScrubbingLogFormatter new]; [DDLog addLogger:self.fileLogger]; @@ -133,3 +136,5 @@ } @end + +NS_ASSUME_NONNULL_END From 4bbf0d9e3d27ee76c75c33a5050686c162336613 Mon Sep 17 00:00:00 2001 From: Matthew Chen Date: Fri, 2 Mar 2018 10:04:15 -0500 Subject: [PATCH 10/16] Integrate with logs service. --- Pods | 2 +- Signal/src/AppDelegate.m | 3 + Signal/src/util/Pastelog.m | 198 ++++++++++++++++----------- SignalServiceKit/src/Util/OWSError.h | 3 +- 4 files changed, 124 insertions(+), 82 deletions(-) diff --git a/Pods b/Pods index 29babe215..54aac3475 160000 --- a/Pods +++ b/Pods @@ -1 +1 @@ -Subproject commit 29babe215072d52688ea5b18592f308bfc190612 +Subproject commit 54aac3475a78b5633781c440f2596da4c66ec6d9 diff --git a/Signal/src/AppDelegate.m b/Signal/src/AppDelegate.m index 254dc626d..510492654 100644 --- a/Signal/src/AppDelegate.m +++ b/Signal/src/AppDelegate.m @@ -1112,6 +1112,9 @@ static NSString *const kURLHostVerifyPrefix = @"verify"; [OWSPreferences setIsReadyForAppExtensions]; [self ensureRootViewController]; + + // TODO: Remove + [Pastelog submitLogs]; } - (void)registrationStateDidChange diff --git a/Signal/src/util/Pastelog.m b/Signal/src/util/Pastelog.m index f0d6fd907..b201b8cb4 100644 --- a/Signal/src/util/Pastelog.m +++ b/Signal/src/util/Pastelog.m @@ -5,6 +5,7 @@ #import "Pastelog.h" #import "Signal-Swift.h" #import "ThreadUtil.h" +#import #import #import #import @@ -14,6 +15,9 @@ #import #import +// TODO: Remove +#import "NSData+hexString.h" + NS_ASSUME_NONNULL_BEGIN typedef void (^UploadDebugLogsSuccess)(NSURL *url); @@ -26,9 +30,10 @@ typedef void (^UploadDebugLogsFailure)(NSString *localizedErrorMessage); typedef void (^DebugLogUploadSuccess)(DebugLogUploader *uploader, NSURL *url); typedef void (^DebugLogUploadFailure)(DebugLogUploader *uploader, NSError *error); -@interface DebugLogUploader : NSObject +@interface DebugLogUploader : NSObject -@property (nonatomic) NSMutableData *responseData; +@property (nonatomic) NSURL *fileUrl; +@property (nonatomic) NSString *mimeType; @property (nonatomic, nullable) DebugLogUploadSuccess success; @property (nonatomic, nullable) DebugLogUploadFailure failure; @@ -43,103 +48,135 @@ typedef void (^DebugLogUploadFailure)(DebugLogUploader *uploader, NSError *error DDLogVerbose(@"Dealloc: %@", self.logTag); } -- (void)uploadFileWithURL:(NSURL *)fileUrl success:(DebugLogUploadSuccess)success failure:(DebugLogUploadFailure)failure +- (void)uploadFileWithURL:(NSURL *)fileUrl + mimeType:(NSString *)mimeType + success:(DebugLogUploadSuccess)success + failure:(DebugLogUploadFailure)failure { OWSAssert(fileUrl); + OWSAssert(mimeType.length > 0); OWSAssert(success); OWSAssert(failure); + self.fileUrl = fileUrl; + self.mimeType = mimeType; self.success = success; self.failure = failure; - self.responseData = [NSMutableData new]; - NSURL *url = [NSURL URLWithString:@"https://filebin.net"]; + // TODO: Remove + NSData *data = [NSData dataWithContentsOfURL:fileUrl]; + DDLogInfo(@"%@ data: %zd", self.logTag, data.length); + NSData *header = [data subdataWithRange:NSMakeRange(0, MIN((NSUInteger)256, data.length))]; + NSString *hexString = [header hexadecimalString]; + DDLogInfo(@"%@ hexString: %@", self.logTag, hexString); - NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:url - cachePolicy:NSURLRequestReloadIgnoringLocalCacheData - timeoutInterval:30]; - [request setHTTPMethod:@"POST"]; - [request addValue:fileUrl.lastPathComponent forHTTPHeaderField:@"filename"]; - [request addValue:@"application/zip" forHTTPHeaderField:@"Content-Type"]; - NSData *_Nullable data = [NSData dataWithContentsOfURL:fileUrl]; - if (!data) { - [self failWithError:[NSError errorWithDomain:@"PastelogKit" - code:10002 - userInfo:@{ NSLocalizedDescriptionKey : @"Could not load data." }]]; - return; - } - // TODO: - [request setHTTPBody:data]; - - NSURLConnection *connection = [NSURLConnection connectionWithRequest:request delegate:self]; - [connection start]; + [self getUploadParameters]; } -#pragma mark - Delegate Methods - -- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data +- (void)getUploadParameters { - DDLogVerbose(@"%@ %s", self.logTag, __PRETTY_FUNCTION__); + __weak DebugLogUploader *weakSelf = self; - [self.responseData appendData:data]; + // TODO: Remove + // The JSON object it returns has two elements, URL, and "fields". Just POST to "ur" with a multipart/form-data body + // that has each KV pair in "fields" encoded as a form element. Add your file, called "file", and what you post will + // be at debuglogs.org/fields['key'] + + NSURLSessionConfiguration *sessionConf = NSURLSessionConfiguration.ephemeralSessionConfiguration; + AFHTTPSessionManager *sessionManager = + [[AFHTTPSessionManager alloc] initWithBaseURL:nil sessionConfiguration:sessionConf]; + sessionManager.requestSerializer = [AFHTTPRequestSerializer serializer]; + sessionManager.responseSerializer = [AFJSONResponseSerializer serializer]; + NSString *urlString = @"https://debuglogs.org/"; + [sessionManager GET:urlString + parameters:nil + progress:nil + success:^(NSURLSessionDataTask *task, id _Nullable responseObject) { + if (![responseObject isKindOfClass:[NSDictionary class]]) { + DDLogError(@"%@ Invalid response: %@, %@", weakSelf.logTag, urlString, responseObject); + [weakSelf + failWithError:OWSErrorWithCodeDescription(OWSErrorCodeDebugLogUploadFailed, @"Invalid response")]; + return; + } + NSString *uploadUrl = responseObject[@"url"]; + if (![uploadUrl isKindOfClass:[NSString class]] || uploadUrl.length < 1) { + DDLogError(@"%@ Invalid response: %@, %@", weakSelf.logTag, urlString, responseObject); + [weakSelf + failWithError:OWSErrorWithCodeDescription(OWSErrorCodeDebugLogUploadFailed, @"Invalid response")]; + return; + } + NSDictionary *fields = responseObject[@"fields"]; + if (![fields isKindOfClass:[NSDictionary class]] || fields.count < 1) { + DDLogError(@"%@ Invalid response: %@, %@", weakSelf.logTag, urlString, responseObject); + [weakSelf + failWithError:OWSErrorWithCodeDescription(OWSErrorCodeDebugLogUploadFailed, @"Invalid response")]; + return; + } + for (NSString *fieldName in fields) { + NSString *fieldValue = fields[fieldName]; + if (![fieldName isKindOfClass:[NSString class]] || fieldName.length < 1 + || ![fieldValue isKindOfClass:[NSString class]] || fieldValue.length < 1) { + DDLogError(@"%@ Invalid response: %@, %@", weakSelf.logTag, urlString, responseObject); + [weakSelf failWithError:OWSErrorWithCodeDescription( + OWSErrorCodeDebugLogUploadFailed, @"Invalid response")]; + return; + } + } + NSString *_Nullable uploadKey = fields[@"key"]; + if (![uploadKey isKindOfClass:[NSString class]] || uploadKey.length < 1) { + DDLogError(@"%@ Invalid response: %@, %@", weakSelf.logTag, urlString, responseObject); + [weakSelf + failWithError:OWSErrorWithCodeDescription(OWSErrorCodeDebugLogUploadFailed, @"Invalid response")]; + return; + } + [weakSelf uploadFileWithUploadUrl:uploadUrl fields:fields uploadKey:uploadKey]; + } + failure:^(NSURLSessionDataTask *_Nullable task, NSError *error) { + DDLogError(@"%@ failed: %@", weakSelf.logTag, urlString); + [weakSelf failWithError:error]; + }]; } -- (void)connectionDidFinishLoading:(NSURLConnection *)connection +- (void)uploadFileWithUploadUrl:(NSString *)uploadUrl fields:(NSDictionary *)fields uploadKey:(NSString *)uploadKey { - DDLogVerbose(@"%@ %s", self.logTag, __PRETTY_FUNCTION__); + OWSAssert(uploadUrl.length > 0); + OWSAssert(fields); + OWSAssert(uploadKey.length > 0); - NSError *error; - NSDictionary *_Nullable dict = [NSJSONSerialization JSONObjectWithData:self.responseData options:0 error:&error]; - if (error) { - DDLogError(@"%@ response length: %zd", self.logTag, self.responseData.length); - [self failWithError:error]; - return; - } + __weak DebugLogUploader *weakSelf = self; + NSURLSessionConfiguration *sessionConf = NSURLSessionConfiguration.ephemeralSessionConfiguration; + AFHTTPSessionManager *sessionManager = + [[AFHTTPSessionManager alloc] initWithBaseURL:nil sessionConfiguration:sessionConf]; + sessionManager.requestSerializer = [AFHTTPRequestSerializer serializer]; + sessionManager.responseSerializer = [AFJSONResponseSerializer serializer]; + [sessionManager POST:uploadUrl + parameters:@{} + constructingBodyWithBlock:^(id formData) { + for (NSString *fieldName in fields) { + NSString *fieldValue = fields[fieldName]; + [formData appendPartWithFormData:[fieldValue dataUsingEncoding:NSUTF8StringEncoding] name:fieldName]; + } + NSError *error; + BOOL success = [formData appendPartWithFileURL:weakSelf.fileUrl + name:@"file" + fileName:weakSelf.fileUrl.lastPathComponent + mimeType:weakSelf.mimeType + error:&error]; + if (!success || error) { + DDLogError(@"%@ failed: %@, error: %@", weakSelf.logTag, uploadUrl, error); + } + } + progress:nil + success:^(NSURLSessionDataTask *task, id _Nullable responseObject) { + DDLogVerbose(@"%@ Response: %@, %@", weakSelf.logTag, uploadUrl, responseObject); - if (![dict isKindOfClass:[NSDictionary class]]) { - DDLogError(@"%@ response (1): %@", self.logTag, dict); - [self failWithError:[NSError errorWithDomain:@"PastelogKit" - code:10003 - userInfo:@{ NSLocalizedDescriptionKey : @"Malformed response (root)." }]]; - return; - } - - NSArray *_Nullable links = [dict objectForKey:@"links"]; - if (![links isKindOfClass:[NSArray class]]) { - DDLogError(@"%@ response (2): %@", self.logTag, dict); - [self failWithError:[NSError errorWithDomain:@"PastelogKit" - code:10004 - userInfo:@{ NSLocalizedDescriptionKey : @"Malformed response (links)." }]]; - return; - } - NSString *_Nullable urlString = nil; - for (NSDictionary *linkMap in links) { - if (![linkMap isKindOfClass:[NSDictionary class]]) { - DDLogError(@"%@ response (2): %@", self.logTag, dict); - [self failWithError:[NSError - errorWithDomain:@"PastelogKit" - code:10005 - userInfo:@{ NSLocalizedDescriptionKey : @"Malformed response (linkMap)." }]]; - return; + NSString *urlString = [NSString stringWithFormat:@"https://debuglogs.org/%@", uploadKey]; + [self succeedWithUrl:[NSURL URLWithString:urlString]]; } - NSString *_Nullable linkRel = [linkMap objectForKey:@"rel"]; - if (![linkRel isKindOfClass:[NSString class]]) { - DDLogError(@"%@ response (linkRel): %@", self.logTag, dict); - continue; - } - if (![linkRel isEqualToString:@"file"]) { - DDLogError(@"%@ response (linkRel value): %@", self.logTag, dict); - continue; - } - NSString *_Nullable linkHref = [linkMap objectForKey:@"href"]; - if (![linkHref isKindOfClass:[NSString class]]) { - DDLogError(@"%@ response (linkHref): %@", self.logTag, dict); - continue; - } - urlString = linkHref; - break; - } - [self succeedWithUrl:[NSURL URLWithString:urlString]]; + failure:^(NSURLSessionDataTask *_Nullable task, NSError *error) { + DDLogError(@"%@ failed: %@", weakSelf.logTag, uploadUrl); + [weakSelf failWithError:error]; + }]; } - (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response @@ -383,6 +420,7 @@ typedef void (^DebugLogUploadFailure)(DebugLogUploader *uploader, NSError *error __weak Pastelog *weakSelf = self; self.currentUploader = [DebugLogUploader new]; [self.currentUploader uploadFileWithURL:[NSURL fileURLWithPath:zipFilePath] + mimeType:@"application/zip" success:^(DebugLogUploader *uploader, NSURL *url) { if (uploader != weakSelf.currentUploader) { // Ignore events from obsolete uploaders. diff --git a/SignalServiceKit/src/Util/OWSError.h b/SignalServiceKit/src/Util/OWSError.h index 828d5401f..07a45610e 100644 --- a/SignalServiceKit/src/Util/OWSError.h +++ b/SignalServiceKit/src/Util/OWSError.h @@ -28,7 +28,8 @@ typedef NS_ENUM(NSInteger, OWSErrorCode) { OWSErrorCodeCouldNotWriteAttachmentData = 777409, OWSErrorCodeMessageDeletedBeforeSent = 777410, OWSErrorCodeDatabaseConversionFatalError = 777411, - OWSErrorCodeMoveFileToSharedDataContainerError = 777412 + OWSErrorCodeMoveFileToSharedDataContainerError = 777412, + OWSErrorCodeDebugLogUploadFailed = 777414, }; extern NSString *const OWSErrorRecipientIdentifierKey; From 7b84afaaf172e6d22fdd7debf7da9e9fbc07fe66 Mon Sep 17 00:00:00 2001 From: Matthew Chen Date: Fri, 2 Mar 2018 13:43:09 -0500 Subject: [PATCH 11/16] Integrate with logs service. --- Scripts/debug_log_upload.py | 64 +++++++++++++++++++++++++++++++++ Signal/src/AppDelegate.m | 3 -- Signal/src/util/Pastelog.m | 71 ++++++++++++++++++------------------- 3 files changed, 99 insertions(+), 39 deletions(-) create mode 100755 Scripts/debug_log_upload.py diff --git a/Scripts/debug_log_upload.py b/Scripts/debug_log_upload.py new file mode 100755 index 000000000..0c26aafb4 --- /dev/null +++ b/Scripts/debug_log_upload.py @@ -0,0 +1,64 @@ +#!/usr/bin/env python +import sys +import os +import re +import commands +import subprocess +import argparse +import inspect +import urllib2 +import json + +def fail(message): + file_name = __file__ + current_line_no = inspect.stack()[1][2] + current_function_name = inspect.stack()[1][3] + print 'Failure in:', file_name, current_line_no, current_function_name + print message + sys.exit(1) + + +def execute_command(command): + try: + print ' '.join(command) + output = subprocess.check_output(command) + if output: + print output + except subprocess.CalledProcessError as e: + print e.output + sys.exit(1) + + +if __name__ == '__main__': + parser = argparse.ArgumentParser(description='Precommit cleanup script.') + parser.add_argument('--file', help='used for starting a new version.') + + args = parser.parse_args() + + params_response = urllib2.urlopen("https://debuglogs.org/").read() + + params = json.loads(params_response) + + upload_url = params['url'] + upload_fields = params['fields'] + upload_key = upload_fields['key'] + upload_key = upload_key + os.path.splitext(args.file)[1] + upload_fields['key'] = upload_key + + download_url = 'https://debuglogs.org/' + upload_key + print 'download_url:', download_url + + curl_command = ['curl', '-v', '-i', '-X', 'POST'] + for field_name in upload_fields: + field_value = upload_fields[field_name] + curl_command.append('-F') + curl_command.append("'%s=%s'" % (field_name, field_value, )) + curl_command.append('-F') + curl_command.append("'file=@%s'" % (args.file,)) + curl_command.append(upload_url) + + # execute_command(curl_command) + print ' '.join(curl_command) + + print 'download_url:', download_url + \ No newline at end of file diff --git a/Signal/src/AppDelegate.m b/Signal/src/AppDelegate.m index 510492654..254dc626d 100644 --- a/Signal/src/AppDelegate.m +++ b/Signal/src/AppDelegate.m @@ -1112,9 +1112,6 @@ static NSString *const kURLHostVerifyPrefix = @"verify"; [OWSPreferences setIsReadyForAppExtensions]; [self ensureRootViewController]; - - // TODO: Remove - [Pastelog submitLogs]; } - (void)registrationStateDidChange diff --git a/Signal/src/util/Pastelog.m b/Signal/src/util/Pastelog.m index b201b8cb4..a4f602907 100644 --- a/Signal/src/util/Pastelog.m +++ b/Signal/src/util/Pastelog.m @@ -5,6 +5,7 @@ #import "Pastelog.h" #import "Signal-Swift.h" #import "ThreadUtil.h" +#import "zlib.h" #import #import #import @@ -15,9 +16,6 @@ #import #import -// TODO: Remove -#import "NSData+hexString.h" - NS_ASSUME_NONNULL_BEGIN typedef void (^UploadDebugLogsSuccess)(NSURL *url); @@ -63,13 +61,6 @@ typedef void (^DebugLogUploadFailure)(DebugLogUploader *uploader, NSError *error self.success = success; self.failure = failure; - // TODO: Remove - NSData *data = [NSData dataWithContentsOfURL:fileUrl]; - DDLogInfo(@"%@ data: %zd", self.logTag, data.length); - NSData *header = [data subdataWithRange:NSMakeRange(0, MIN((NSUInteger)256, data.length))]; - NSString *hexString = [header hexadecimalString]; - DDLogInfo(@"%@ hexString: %@", self.logTag, hexString); - [self getUploadParameters]; } @@ -77,11 +68,6 @@ typedef void (^DebugLogUploadFailure)(DebugLogUploader *uploader, NSError *error { __weak DebugLogUploader *weakSelf = self; - // TODO: Remove - // The JSON object it returns has two elements, URL, and "fields". Just POST to "ur" with a multipart/form-data body - // that has each KV pair in "fields" encoded as a form element. Add your file, called "file", and what you post will - // be at debuglogs.org/fields['key'] - NSURLSessionConfiguration *sessionConf = NSURLSessionConfiguration.ephemeralSessionConfiguration; AFHTTPSessionManager *sessionManager = [[AFHTTPSessionManager alloc] initWithBaseURL:nil sessionConfiguration:sessionConf]; @@ -129,6 +115,8 @@ typedef void (^DebugLogUploadFailure)(DebugLogUploader *uploader, NSError *error failWithError:OWSErrorWithCodeDescription(OWSErrorCodeDebugLogUploadFailed, @"Invalid response")]; return; } + NSString *fileExtension = weakSelf.fileUrl.lastPathComponent.pathExtension; + uploadKey = [uploadKey stringByAppendingPathExtension:fileExtension]; [weakSelf uploadFileWithUploadUrl:uploadUrl fields:fields uploadKey:uploadKey]; } failure:^(NSURLSessionDataTask *_Nullable task, NSError *error) { @@ -148,7 +136,7 @@ typedef void (^DebugLogUploadFailure)(DebugLogUploader *uploader, NSError *error AFHTTPSessionManager *sessionManager = [[AFHTTPSessionManager alloc] initWithBaseURL:nil sessionConfiguration:sessionConf]; sessionManager.requestSerializer = [AFHTTPRequestSerializer serializer]; - sessionManager.responseSerializer = [AFJSONResponseSerializer serializer]; + sessionManager.responseSerializer = [AFHTTPResponseSerializer serializer]; [sessionManager POST:uploadUrl parameters:@{} constructingBodyWithBlock:^(id formData) { @@ -297,7 +285,7 @@ typedef void (^DebugLogUploadFailure)(DebugLogUploader *uploader, NSError *error actionWithTitle:NSLocalizedString(@"DEBUG_LOG_ALERT_OPTION_EMAIL", @"Label for the 'email debug log' option of the the debug log alert.") style:UIAlertActionStyleDefault - handler:^(UIAlertAction *_Nonnull action) { + handler:^(UIAlertAction *action) { [Pastelog.sharedManager submitEmail:url]; completion(); @@ -306,7 +294,7 @@ typedef void (^DebugLogUploadFailure)(DebugLogUploader *uploader, NSError *error actionWithTitle:NSLocalizedString(@"DEBUG_LOG_ALERT_OPTION_COPY_LINK", @"Label for the 'copy link' option of the the debug log alert.") style:UIAlertActionStyleDefault - handler:^(UIAlertAction *_Nonnull action) { + handler:^(UIAlertAction *action) { UIPasteboard *pb = [UIPasteboard generalPasteboard]; [pb setString:url.absoluteString]; @@ -317,7 +305,7 @@ typedef void (^DebugLogUploadFailure)(DebugLogUploader *uploader, NSError *error actionWithTitle:NSLocalizedString(@"DEBUG_LOG_ALERT_OPTION_SEND_TO_SELF", @"Label for the 'send to self' option of the the debug log alert.") style:UIAlertActionStyleDefault - handler:^(UIAlertAction *_Nonnull action) { + handler:^(UIAlertAction *action) { [Pastelog.sharedManager sendToSelf:url]; }]]; [alert @@ -325,7 +313,7 @@ typedef void (^DebugLogUploadFailure)(DebugLogUploader *uploader, NSError *error actionWithTitle:NSLocalizedString(@"DEBUG_LOG_ALERT_OPTION_SEND_TO_LAST_THREAD", @"Label for the 'send to last thread' option of the the debug log alert.") style:UIAlertActionStyleDefault - handler:^(UIAlertAction *_Nonnull action) { + handler:^(UIAlertAction *action) { [Pastelog.sharedManager sendToMostRecentThread:url]; }]]; #endif @@ -334,7 +322,7 @@ typedef void (^DebugLogUploadFailure)(DebugLogUploader *uploader, NSError *error actionWithTitle:NSLocalizedString(@"DEBUG_LOG_ALERT_OPTION_BUG_REPORT", @"Label for the 'Open a Bug Report' option of the the debug log alert.") style:UIAlertActionStyleCancel - handler:^(UIAlertAction *_Nonnull action) { + handler:^(UIAlertAction *action) { [Pastelog.sharedManager prepareRedirection:url completion:completion]; }]]; UIViewController *presentingViewController @@ -404,8 +392,13 @@ typedef void (^DebugLogUploadFailure)(DebugLogUploader *uploader, NSError *error } // Phase 2. Zip up the log files. - BOOL zipSuccess = - [SSZipArchive createZipFileAtPath:zipFilePath withContentsOfDirectory:zipDirPath withPassword:nil]; + BOOL zipSuccess = [SSZipArchive createZipFileAtPath:zipFilePath + withContentsOfDirectory:zipDirPath + keepParentDirectory:YES + compressionLevel:Z_DEFAULT_COMPRESSION + password:nil + AES:NO + progressHandler:nil]; if (!zipSuccess) { failure(NSLocalizedString( @"DEBUG_LOG_ALERT_COULD_NOT_PACKAGE_LOGS", @"Error indicating that the debug logs could not be packaged.")); @@ -460,7 +453,11 @@ typedef void (^DebugLogUploadFailure)(DebugLogUploader *uploader, NSError *error { NSString *emailAddress = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"LOGS_EMAIL"]; - NSString *urlString = [NSString stringWithString: [[NSString stringWithFormat:@"mailto:%@?subject=iOS%%20Debug%%20Log&body=", emailAddress] stringByAppendingString:[[NSString stringWithFormat:@"Log URL: %@ \n Tell us about the issue: ", url]stringByAddingPercentEscapesUsingEncoding:NSASCIIStringEncoding]]]; + NSString *body = [NSString stringWithFormat:@"Log URL: %@ \n Tell us about the issue: ", url]; + NSString *escapedBody = + [body stringByAddingPercentEncodingWithAllowedCharacters:NSCharacterSet.URLQueryAllowedCharacterSet]; + NSString *urlString = + [NSString stringWithFormat:@"mailto:%@?subject=iOS%%20Debug%%20Log&body=%@", emailAddress, escapedBody]; [UIApplication.sharedApplication openURL:[NSURL URLWithString:urlString]]; } @@ -481,7 +478,7 @@ typedef void (^DebugLogUploadFailure)(DebugLogUploader *uploader, NSError *error [alert addAction:[UIAlertAction actionWithTitle:NSLocalizedString(@"OK", @"") style:UIAlertActionStyleDefault - handler:^(UIAlertAction *_Nonnull action) { + handler:^(UIAlertAction *action) { [UIApplication.sharedApplication openURL:[NSURL URLWithString:[[NSBundle mainBundle] objectForInfoDictionaryKey:@"LOGS_URL"]]]; @@ -502,10 +499,9 @@ typedef void (^DebugLogUploadFailure)(DebugLogUploader *uploader, NSError *error DispatchMainThreadSafe(^{ __block TSThread *thread = nil; - [TSStorageManager.dbReadWriteConnection - readWriteWithBlock:^(YapDatabaseReadWriteTransaction *_Nonnull transaction) { - thread = [TSContactThread getOrCreateThreadWithContactId:recipientId transaction:transaction]; - }]; + [TSStorageManager.dbReadWriteConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) { + thread = [TSContactThread getOrCreateThreadWithContactId:recipientId transaction:transaction]; + }]; [ThreadUtil sendMessageWithText:url.absoluteString inThread:thread messageSender:messageSender]; }); @@ -518,15 +514,18 @@ typedef void (^DebugLogUploadFailure)(DebugLogUploader *uploader, NSError *error if (![TSAccountManager isRegistered]) { return; } - OWSMessageSender *messageSender = Environment.current.messageSender; + __block TSThread *thread = nil; + [TSStorageManager.dbReadConnection readWithBlock:^(YapDatabaseReadTransaction *transaction) { + thread = [[transaction ext:TSThreadDatabaseViewExtensionName] firstObjectInGroup:TSInboxGroup]; + }]; DispatchMainThreadSafe(^{ - __block TSThread *thread = nil; - [TSStorageManager.dbReadWriteConnection - readWriteWithBlock:^(YapDatabaseReadWriteTransaction *_Nonnull transaction) { - thread = [[transaction ext:TSThreadDatabaseViewExtensionName] firstObjectInGroup:[TSThread collection]]; - }]; - [ThreadUtil sendMessageWithText:url.absoluteString inThread:thread messageSender:messageSender]; + if (thread) { + OWSMessageSender *messageSender = Environment.current.messageSender; + [ThreadUtil sendMessageWithText:url.absoluteString inThread:thread messageSender:messageSender]; + } else { + [Pastelog showFailureAlertWithMessage:@"Could not find last thread."]; + } }); // Also copy to pasteboard. From 256a300297a754eae58dc05d3f44ff4e4211867a Mon Sep 17 00:00:00 2001 From: Matthew Chen Date: Fri, 2 Mar 2018 13:51:22 -0500 Subject: [PATCH 12/16] Integrate with logs service. --- Signal/src/util/Pastelog.m | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/Signal/src/util/Pastelog.m b/Signal/src/util/Pastelog.m index a4f602907..f5322086a 100644 --- a/Signal/src/util/Pastelog.m +++ b/Signal/src/util/Pastelog.m @@ -115,9 +115,14 @@ typedef void (^DebugLogUploadFailure)(DebugLogUploader *uploader, NSError *error failWithError:OWSErrorWithCodeDescription(OWSErrorCodeDebugLogUploadFailed, @"Invalid response")]; return; } + + // Add a file extension to the upload's key. NSString *fileExtension = weakSelf.fileUrl.lastPathComponent.pathExtension; uploadKey = [uploadKey stringByAppendingPathExtension:fileExtension]; - [weakSelf uploadFileWithUploadUrl:uploadUrl fields:fields uploadKey:uploadKey]; + NSMutableDictionary *updatedFields = [fields mutableCopy]; + updatedFields[@"key"] = uploadKey; + + [weakSelf uploadFileWithUploadUrl:uploadUrl fields:updatedFields uploadKey:uploadKey]; } failure:^(NSURLSessionDataTask *_Nullable task, NSError *error) { DDLogError(@"%@ failed: %@", weakSelf.logTag, urlString); From 4834a85fb5d90eab39587cab7fa674e98d488883 Mon Sep 17 00:00:00 2001 From: Matthew Chen Date: Fri, 2 Mar 2018 14:29:53 -0500 Subject: [PATCH 13/16] Add share option for debug logs. --- Signal/src/util/Pastelog.m | 11 ++++++- .../translations/en.lproj/Localizable.strings | 3 ++ .../attachments/AttachmentSharing.h | 10 +++++++ .../attachments/AttachmentSharing.m | 29 ++++++++++++++++--- 4 files changed, 48 insertions(+), 5 deletions(-) diff --git a/Signal/src/util/Pastelog.m b/Signal/src/util/Pastelog.m index f5322086a..17dda81a0 100644 --- a/Signal/src/util/Pastelog.m +++ b/Signal/src/util/Pastelog.m @@ -8,6 +8,7 @@ #import "zlib.h" #import #import +#import #import #import #import @@ -326,10 +327,18 @@ typedef void (^DebugLogUploadFailure)(DebugLogUploader *uploader, NSError *error addAction:[UIAlertAction actionWithTitle:NSLocalizedString(@"DEBUG_LOG_ALERT_OPTION_BUG_REPORT", @"Label for the 'Open a Bug Report' option of the the debug log alert.") - style:UIAlertActionStyleCancel + style:UIAlertActionStyleDefault handler:^(UIAlertAction *action) { [Pastelog.sharedManager prepareRedirection:url completion:completion]; }]]; + [alert addAction:[UIAlertAction actionWithTitle:NSLocalizedString(@"DEBUG_LOG_ALERT_OPTION_SHARE", + @"Label for the 'Share' option of the the debug log alert.") + style:UIAlertActionStyleDefault + handler:^(UIAlertAction *action) { + [AttachmentSharing showShareUIForText:url.absoluteString + completion:completion]; + }]]; + [alert addAction:[OWSAlerts cancelAction]]; UIViewController *presentingViewController = UIApplication.sharedApplication.frontmostViewControllerIgnoringAlerts; [presentingViewController presentViewController:alert animated:NO completion:nil]; diff --git a/Signal/translations/en.lproj/Localizable.strings b/Signal/translations/en.lproj/Localizable.strings index 9a973d039..7bc110c58 100644 --- a/Signal/translations/en.lproj/Localizable.strings +++ b/Signal/translations/en.lproj/Localizable.strings @@ -529,6 +529,9 @@ /* Label for the 'send to self' option of the the debug log alert. */ "DEBUG_LOG_ALERT_OPTION_SEND_TO_SELF" = "Send to Self"; +/* Label for the 'Share' option of the the debug log alert. */ +"DEBUG_LOG_ALERT_OPTION_SHARE" = "Share"; + /* Title of the alert shown for failures while uploading debug logs. Title of the debug log alert. */ "DEBUG_LOG_ALERT_TITLE" = "One More Step"; diff --git a/SignalMessaging/attachments/AttachmentSharing.h b/SignalMessaging/attachments/AttachmentSharing.h index 66bf2b833..712c77157 100644 --- a/SignalMessaging/attachments/AttachmentSharing.h +++ b/SignalMessaging/attachments/AttachmentSharing.h @@ -2,18 +2,28 @@ // Copyright (c) 2018 Open Whisper Systems. All rights reserved. // +NS_ASSUME_NONNULL_BEGIN + @class TSAttachmentStream; +typedef void (^AttachmentSharingCompletion)(void); + @interface AttachmentSharing : NSObject + (void)showShareUIForAttachment:(TSAttachmentStream *)stream; + (void)showShareUIForURL:(NSURL *)url; ++ (void)showShareUIForURL:(NSURL *)url completion:(nullable AttachmentSharingCompletion)completion; + + (void)showShareUIForText:(NSString *)text; ++ (void)showShareUIForText:(NSString *)text completion:(nullable AttachmentSharingCompletion)completion; + #ifdef DEBUG + (void)showShareUIForUIImage:(UIImage *)image; #endif @end + +NS_ASSUME_NONNULL_END diff --git a/SignalMessaging/attachments/AttachmentSharing.m b/SignalMessaging/attachments/AttachmentSharing.m index 7508a3645..c648ccd18 100644 --- a/SignalMessaging/attachments/AttachmentSharing.m +++ b/SignalMessaging/attachments/AttachmentSharing.m @@ -8,6 +8,8 @@ #import #import +NS_ASSUME_NONNULL_BEGIN + @implementation AttachmentSharing + (void)showShareUIForAttachment:(TSAttachmentStream *)stream @@ -18,21 +20,33 @@ } + (void)showShareUIForURL:(NSURL *)url +{ + [self showShareUIForURL:url completion:nil]; +} + ++ (void)showShareUIForURL:(NSURL *)url completion:(nullable AttachmentSharingCompletion)completion { OWSAssert(url); [AttachmentSharing showShareUIForActivityItems:@[ url, - ]]; + ] + completion:completion]; } + (void)showShareUIForText:(NSString *)text +{ + [self showShareUIForText:text completion:nil]; +} + ++ (void)showShareUIForText:(NSString *)text completion:(nullable AttachmentSharingCompletion)completion { OWSAssert(text); [AttachmentSharing showShareUIForActivityItems:@[ text, - ]]; + ] + completion:completion]; } #ifdef DEBUG @@ -42,11 +56,12 @@ [AttachmentSharing showShareUIForActivityItems:@[ image, - ]]; + ] + completion:nil]; } #endif -+ (void)showShareUIForActivityItems:(NSArray *)activityItems ++ (void)showShareUIForActivityItems:(NSArray *)activityItems completion:(nullable AttachmentSharingCompletion)completion { OWSAssert(activityItems); @@ -67,6 +82,10 @@ } else if (completed) { DDLogInfo(@"%@ Did share with activityType: %@", self.logTag, activityType); } + + if (completion) { + DispatchMainThreadSafe(completion); + } }]; UIViewController *fromViewController = CurrentAppContext().frontmostViewController; @@ -84,3 +103,5 @@ } @end + +NS_ASSUME_NONNULL_END From 864f1cc8ee59c85c5440ead47ee62fc9b721b775 Mon Sep 17 00:00:00 2001 From: Matthew Chen Date: Fri, 2 Mar 2018 14:37:37 -0500 Subject: [PATCH 14/16] Clean up ahead of PR. --- SignalMessaging/utils/DebugLogger.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SignalMessaging/utils/DebugLogger.m b/SignalMessaging/utils/DebugLogger.m index bb306982f..9d859c6e5 100644 --- a/SignalMessaging/utils/DebugLogger.m +++ b/SignalMessaging/utils/DebugLogger.m @@ -70,7 +70,7 @@ const NSUInteger kMaxDebugLogFileSize = 1024 * 1024 * 3; // 24 hour rolling. self.fileLogger.rollingFrequency = kDayInterval; // Keep last 3 days of logs - or last 3 logs (if logs rollover due to max file size). - self.fileLogger.logFileManager.maximumNumberOfLogFiles = 24; + self.fileLogger.logFileManager.maximumNumberOfLogFiles = 3; self.fileLogger.maximumFileSize = kMaxDebugLogFileSize; self.fileLogger.logFormatter = [OWSScrubbingLogFormatter new]; From fa07b77ad9eb3ab0ea715d9e0f6e93d00d81aa01 Mon Sep 17 00:00:00 2001 From: Matthew Chen Date: Fri, 2 Mar 2018 17:48:24 -0500 Subject: [PATCH 15/16] Update cocoapods. --- Gemfile.lock | 86 ++++++++++++++++++++++++++++------------------------ Podfile.lock | 4 +-- Pods | 2 +- 3 files changed, 50 insertions(+), 42 deletions(-) diff --git a/Gemfile.lock b/Gemfile.lock index c58a26a6b..a26d67633 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,7 +1,7 @@ GEM remote: https://rubygems.org/ specs: - CFPropertyList (2.3.5) + CFPropertyList (2.3.6) activesupport (4.2.10) i18n (~> 0.7) minitest (~> 5.1) @@ -9,32 +9,33 @@ GEM tzinfo (~> 1.1) addressable (2.5.2) public_suffix (>= 2.0.2, < 4.0) + atomos (0.1.2) babosa (1.0.2) claide (1.0.2) - cocoapods (1.3.1) + cocoapods (1.4.0) activesupport (>= 4.0.2, < 5) claide (>= 1.0.2, < 2.0) - cocoapods-core (= 1.3.1) - cocoapods-deintegrate (>= 1.0.1, < 2.0) + cocoapods-core (= 1.4.0) + cocoapods-deintegrate (>= 1.0.2, < 2.0) cocoapods-downloader (>= 1.1.3, < 2.0) cocoapods-plugins (>= 1.0.0, < 2.0) cocoapods-search (>= 1.0.0, < 2.0) cocoapods-stats (>= 1.0.0, < 2.0) - cocoapods-trunk (>= 1.2.0, < 2.0) + cocoapods-trunk (>= 1.3.0, < 2.0) cocoapods-try (>= 1.1.0, < 2.0) colored2 (~> 3.1) escape (~> 0.0.4) fourflusher (~> 2.0.1) gh_inspector (~> 1.0) - molinillo (~> 0.5.7) + molinillo (~> 0.6.4) nap (~> 1.0) ruby-macho (~> 1.1) - xcodeproj (>= 1.5.1, < 2.0) - cocoapods-core (1.3.1) + xcodeproj (>= 1.5.4, < 2.0) + cocoapods-core (1.4.0) activesupport (>= 4.0.2, < 6) fuzzy_match (~> 2.0.4) nap (~> 1.0) - cocoapods-deintegrate (1.0.1) + cocoapods-deintegrate (1.0.2) cocoapods-downloader (1.1.3) cocoapods-plugins (1.0.0) nap @@ -46,37 +47,38 @@ GEM cocoapods-try (1.1.0) colored (1.2) colored2 (3.1.2) - commander-fastlane (4.4.5) + commander-fastlane (4.4.6) highline (~> 1.7.2) + concurrent-ruby (1.0.5) declarative (0.0.10) declarative-option (0.1.0) domain_name (0.5.20170404) unf (>= 0.0.5, < 1.0.0) dotenv (2.2.1) escape (0.0.4) - excon (0.59.0) - faraday (0.13.1) + excon (0.60.0) + faraday (0.14.0) multipart-post (>= 1.2, < 3) faraday-cookie_jar (0.0.6) faraday (>= 0.7.4) http-cookie (~> 1.0.0) faraday_middleware (0.12.2) faraday (>= 0.7.4, < 1.0) - fastimage (2.1.0) - fastlane (2.60.1) - CFPropertyList (>= 2.3, < 3.0.0) + fastimage (2.1.1) + fastlane (2.84.0) + CFPropertyList (>= 2.3, < 4.0.0) addressable (>= 2.3, < 3.0.0) babosa (>= 1.0.2, < 2.0.0) bundler (>= 1.12.0, < 2.0.0) colored - commander-fastlane (>= 4.4.5, < 5.0.0) + commander-fastlane (>= 4.4.6, < 5.0.0) dotenv (>= 2.1.1, < 3.0.0) excon (>= 0.45.0, < 1.0.0) faraday (~> 0.9) faraday-cookie_jar (~> 0.0.6) faraday_middleware (~> 0.9) fastimage (>= 2.1.0, < 3.0.0) - gh_inspector (>= 1.0.1, < 2.0.0) + gh_inspector (>= 1.1.2, < 2.0.0) google-api-client (>= 0.13.1, < 0.14.0) highline (>= 1.7.2, < 2.0.0) json (< 3.0.0) @@ -88,17 +90,18 @@ GEM public_suffix (~> 2.0.0) rubyzip (>= 1.1.0, < 2.0.0) security (= 0.1.3) - slack-notifier (>= 1.3, < 2.0.0) + slack-notifier (>= 2.0.0, < 3.0.0) terminal-notifier (>= 1.6.2, < 2.0.0) terminal-table (>= 1.4.5, < 2.0.0) - tty-screen (~> 0.5.0) + tty-screen (>= 0.6.3, < 1.0.0) + tty-spinner (>= 0.8.0, < 1.0.0) word_wrap (~> 1.0.0) - xcodeproj (>= 1.5.0, < 2.0.0) + xcodeproj (>= 1.5.2, < 2.0.0) xcpretty (>= 0.2.4, < 1.0.0) xcpretty-travis-formatter (>= 0.0.3) fourflusher (2.0.1) fuzzy_match (2.0.4) - gh_inspector (1.0.3) + gh_inspector (1.1.2) google-api-client (0.13.6) addressable (~> 2.5, >= 2.5.1) googleauth (~> 0.5) @@ -106,21 +109,22 @@ GEM mime-types (~> 3.0) representable (~> 3.0) retriable (>= 2.0, < 4.0) - googleauth (0.5.3) + googleauth (0.6.2) faraday (~> 0.12) - jwt (~> 1.4) + jwt (>= 1.4, < 3.0) logging (~> 2.0) memoist (~> 0.12) multi_json (~> 1.11) os (~> 0.9) signet (~> 0.7) - highline (1.7.8) + highline (1.7.10) http-cookie (1.0.3) domain_name (~> 0.5) httpclient (2.8.3) - i18n (0.8.6) + i18n (0.9.5) + concurrent-ruby (~> 1.0) json (2.1.0) - jwt (1.5.6) + jwt (2.1.0) little-plugger (1.1.4) logging (2.2.2) little-plugger (~> 1.1) @@ -130,16 +134,16 @@ GEM mime-types-data (~> 3.2015) mime-types-data (3.2016.0521) mini_magick (4.5.1) - minitest (5.10.3) - molinillo (0.5.7) - multi_json (1.12.2) + minitest (5.11.3) + molinillo (0.6.4) + multi_json (1.13.1) multi_xml (0.6.0) multipart-post (2.0.0) nanaimo (0.2.3) nap (1.1.0) netrc (0.11.0) os (0.9.6) - plist (3.3.0) + plist (3.4.0) public_suffix (2.0.5) representable (3.0.4) declarative (< 0.1.0) @@ -150,33 +154,37 @@ GEM ruby-macho (1.1.0) rubyzip (1.2.1) security (0.1.3) - signet (0.7.3) + signet (0.8.1) addressable (~> 2.3) faraday (~> 0.9) - jwt (~> 1.5) + jwt (>= 1.5, < 3.0) multi_json (~> 1.10) - slack-notifier (1.5.1) + slack-notifier (2.3.2) terminal-notifier (1.8.0) terminal-table (1.8.0) unicode-display_width (~> 1.1, >= 1.1.1) thread_safe (0.3.6) - tty-screen (0.5.0) - tzinfo (1.2.3) + tty-cursor (0.5.0) + tty-screen (0.6.4) + tty-spinner (0.8.0) + tty-cursor (>= 0.5.0) + tzinfo (1.2.5) thread_safe (~> 0.1) uber (0.1.0) unf (0.1.4) unf_ext - unf_ext (0.0.7.4) + unf_ext (0.0.7.5) unicode-display_width (1.3.0) word_wrap (1.0.0) - xcodeproj (1.5.2) + xcodeproj (1.5.6) CFPropertyList (~> 2.3.3) + atomos (~> 0.1.2) claide (>= 1.0.2, < 2.0) colored2 (~> 3.1) nanaimo (~> 0.2.3) xcpretty (0.2.8) rouge (~> 2.0.7) - xcpretty-travis-formatter (0.0.4) + xcpretty-travis-formatter (1.0.0) xcpretty (~> 0.2, >= 0.0.7) PLATFORMS @@ -187,4 +195,4 @@ DEPENDENCIES fastlane BUNDLED WITH - 1.14.6 + 1.16.1 diff --git a/Podfile.lock b/Podfile.lock index 793848dc7..c63050ed2 100644 --- a/Podfile.lock +++ b/Podfile.lock @@ -211,7 +211,7 @@ SPEC CHECKSUMS: PureLayout: 4d550abe49a94f24c2808b9b95db9131685fe4cd Reachability: 33e18b67625424e47b6cde6d202dce689ad7af96 SAMKeychain: 483e1c9f32984d50ca961e26818a534283b4cd5c - SignalServiceKit: c639443811f2670986006f5b661cb1a862de66ab + SignalServiceKit: 5cc6e8e249f381c5eaee8693c0dff20fc1a3eee0 SocketRocket: dbb1554b8fc288ef8ef370d6285aeca7361be31e SQLCipher: f9fcf29b2e59ced7defc2a2bdd0ebe79b40d4990 SSZipArchive: 14401ade5f8e82aba1ff03e9f88e9de60937ae60 @@ -222,4 +222,4 @@ SPEC CHECKSUMS: PODFILE CHECKSUM: 66db99df53e7593362ebb004bea5d2215ca00e8e -COCOAPODS: 1.3.1 +COCOAPODS: 1.4.0 diff --git a/Pods b/Pods index 54aac3475..e028d806f 160000 --- a/Pods +++ b/Pods @@ -1 +1 @@ -Subproject commit 54aac3475a78b5633781c440f2596da4c66ec6d9 +Subproject commit e028d806f2e2054658e53c4b3c696c2bef8e5755 From aa82f0aa40744a384cb4afb2c61755c6c6be679e Mon Sep 17 00:00:00 2001 From: Michael Kirk Date: Fri, 2 Mar 2018 17:55:27 -0500 Subject: [PATCH 16/16] "Bump build to 2.21.0.1." --- Signal/Signal-Info.plist | 2 +- SignalShareExtension/Info.plist | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Signal/Signal-Info.plist b/Signal/Signal-Info.plist index c1ce8c555..8caf76b20 100644 --- a/Signal/Signal-Info.plist +++ b/Signal/Signal-Info.plist @@ -38,7 +38,7 @@ CFBundleVersion - 2.21.0.0 + 2.21.0.1 ITSAppUsesNonExemptEncryption LOGS_EMAIL diff --git a/SignalShareExtension/Info.plist b/SignalShareExtension/Info.plist index 72464dc24..b81d29e0d 100644 --- a/SignalShareExtension/Info.plist +++ b/SignalShareExtension/Info.plist @@ -19,7 +19,7 @@ CFBundleShortVersionString 2.21.0 CFBundleVersion - 2.21.0.0 + 2.21.0.1 ITSAppUsesNonExemptEncryption NSAppTransportSecurity