identity change vs. share extension

// FREEBIE
This commit is contained in:
sdkjfhsdkjhfsdlkjhfsdf 2017-12-21 17:01:40 -06:00
parent 6b5883dc10
commit 6e2d9c8141
8 changed files with 201 additions and 99 deletions

View File

@ -54,10 +54,6 @@ NS_ASSUME_NONNULL_BEGIN
OWSAssert(flippedKey.length == currentKey.length);
[identityManager saveRemoteIdentity:flippedKey recipientId:recipientId];
}],
[OWSTableItem itemWithTitle:@"Set Verification State"
actionBlock:^{
[DebugUISessionState presentVerificationStatePickerForContactThread:thread];
}],
[OWSTableItem itemWithTitle:@"Delete all sessions"
actionBlock:^{
dispatch_async([OWSDispatch sessionStoreQueue], ^{
@ -81,56 +77,6 @@ NS_ASSUME_NONNULL_BEGIN
]];
}
+ (void)presentVerificationStatePickerForContactThread:(TSContactThread *)contactThread
{
DDLogError(@"%@ Choosing verification state.", self.logTag);
NSString *title = [NSString stringWithFormat:@"Choose verification state for %@", contactThread.name];
UIAlertController *alertController =
[UIAlertController alertControllerWithTitle:title message:nil preferredStyle:UIAlertControllerStyleActionSheet];
NSString *recipientId = [contactThread contactIdentifier];
OWSIdentityManager *identityManger = [OWSIdentityManager sharedManager];
[alertController addAction:[UIAlertAction actionWithTitle:@"Default"
style:UIAlertActionStyleDefault
handler:^(UIAlertAction *_Nonnull action) {
NSData *identityKey =
[identityManger identityKeyForRecipientId:recipientId];
[[OWSIdentityManager sharedManager]
setVerificationState:OWSVerificationStateDefault
identityKey:identityKey
recipientId:recipientId
isUserInitiatedChange:NO];
}]];
[alertController addAction:[UIAlertAction actionWithTitle:@"Verified"
style:UIAlertActionStyleDefault
handler:^(UIAlertAction *_Nonnull action) {
NSData *identityKey =
[identityManger identityKeyForRecipientId:recipientId];
[[OWSIdentityManager sharedManager]
setVerificationState:OWSVerificationStateVerified
identityKey:identityKey
recipientId:recipientId
isUserInitiatedChange:NO];
}]];
[alertController addAction:[UIAlertAction actionWithTitle:@"No Longer Verified"
style:UIAlertActionStyleDefault
handler:^(UIAlertAction *_Nonnull action) {
NSData *identityKey =
[identityManger identityKeyForRecipientId:recipientId];
[[OWSIdentityManager sharedManager]
setVerificationState:OWSVerificationStateNoLongerVerified
identityKey:identityKey
recipientId:recipientId
isUserInitiatedChange:NO];
}]];
[[UIApplication sharedApplication].frontmostViewController presentViewController:alertController
animated:YES
completion:nil];
}
@end
NS_ASSUME_NONNULL_END

View File

@ -1540,6 +1540,9 @@
/* action sheet item */
"SHARE_ACTION_TWEET" = "Twitter";
/* alert body when sharing filefailed because of untrusted/changed identity keys */
"SHARE_EXTENSION_FAILED_SENDING_BECAUSE_UNTRUSTED_IDENTITY_KEY" = "Your safety number with %@ has recently changed. You may wish to verify it in the main app before resending.";
/* Indicates that the share extension is still loading. */
"SHARE_EXTENSION_LOADING" = "Loading...";

View File

@ -11,6 +11,8 @@
#import "UIFont+OWS.h"
#import "UIView+OWS.h"
#import <SignalMessaging/SignalMessaging-Swift.h>
#import <SignalServiceKit/OWSDispatch.h>
#import <SignalServiceKit/OWSError.h>
#import <SignalServiceKit/OWSMessageSender.h>
#import <SignalServiceKit/TSThread.h>
@ -124,26 +126,6 @@ NS_ASSUME_NONNULL_BEGIN
OWSAssert(thread);
self.thread = thread;
__weak typeof(self) weakSelf = self;
// FIXME SHARINGEXTENSION
// Handling safety number changes brings in a lot of machinery.
// How do we want to handle this?
// e.g. fingerprint scanning, etc. in the SAE or just redirect the user to the main app?
// BOOL didShowSNAlert =
// [SafetyNumberConfirmationAlert presentAlertIfNecessaryWithRecipientIds:thread.recipientIdentifiers
// confirmationText:[SafetyNumberStrings
// confirmSendButton]
// contactsManager:self.contactsManager
// completion:^(BOOL didConfirm) {
// if (didConfirm) {
// [weakSelf threadWasSelected:thread];
// }
// }];
// if (didShowSNAlert) {
// return;
// }
AttachmentApprovalViewController *approvalVC =
[[AttachmentApprovalViewController alloc] initWithAttachment:self.attachment delegate:self];
@ -211,7 +193,8 @@ NS_ASSUME_NONNULL_BEGIN
}
#endif
void (^sendCompletion)(NSError *_Nullable) = ^(NSError *_Nullable error) {
void (^sendCompletion)(NSError *_Nullable, TSOutgoingMessage *message) = ^(
NSError *_Nullable error, TSOutgoingMessage *message) {
AssertIsOnMainThread();
if (error) {
@ -220,7 +203,7 @@ NS_ASSUME_NONNULL_BEGIN
completion:^(void) {
DDLogInfo(@"%@ Sending attachment failed with error: %@", self.logTag, error);
[self showSendFailureAlertWithError:error
attachment:attachment
message:message
fromViewController:fromViewController];
}];
return;
@ -233,44 +216,183 @@ NS_ASSUME_NONNULL_BEGIN
[fromViewController presentViewController:progressAlert
animated:YES
completion:^(void) {
TSOutgoingMessage *outgoingMessage =
__block TSOutgoingMessage *outgoingMessage =
[ThreadUtil sendMessageWithAttachment:self.attachment
inThread:self.thread
messageSender:self.messageSender
completion:sendCompletion];
completion:^(NSError *_Nullable error) {
sendCompletion(error, outgoingMessage);
}];
self.outgoingMessage = outgoingMessage;
}];
}
- (void)showSendFailureAlertWithError:(NSError *)error
attachment:(SignalAttachment *)attachment
message:(TSOutgoingMessage *)message
fromViewController:(UIViewController *)fromViewController
{
AssertIsOnMainThread();
OWSAssert(error);
OWSAssert(message);
OWSAssert(fromViewController);
NSString *failureTitle = NSLocalizedString(@"SHARE_EXTENSION_SENDING_FAILURE_TITLE", @"Alert title");
UIAlertController *failureAlert = [UIAlertController alertControllerWithTitle:failureTitle
message:error.localizedDescription
preferredStyle:UIAlertControllerStyleAlert];
if (error.code == OWSErrorCodeUntrustedIdentity) {
NSString *_Nullable untrustedRecipientId = error.userInfo[OWSErrorRecipientIdentifierKey];
UIAlertAction *failureCancelAction = [UIAlertAction actionWithTitle:[CommonStrings cancelButton]
style:UIAlertActionStyleCancel
handler:^(UIAlertAction *_Nonnull action) {
[self.shareViewDelegate shareViewWasCancelled];
}];
[failureAlert addAction:failureCancelAction];
NSString *failureFormat = NSLocalizedString(@"SHARE_EXTENSION_FAILED_SENDING_BECAUSE_UNTRUSTED_IDENTITY_KEY",
@"alert body when sharing filefailed because of untrusted/changed identity keys");
UIAlertAction *retryAction =
[UIAlertAction actionWithTitle:[CommonStrings retryButton]
style:UIAlertActionStyleDefault
handler:^(UIAlertAction *action) {
[self tryToSendAttachment:attachment fromViewController:fromViewController];
}];
[failureAlert addAction:retryAction];
NSString *displayName = [self.contactsManager displayNameForPhoneIdentifier:untrustedRecipientId];
NSString *failureMessage = [NSString stringWithFormat:failureFormat, displayName];
[fromViewController presentViewController:failureAlert animated:YES completion:nil];
UIAlertController *failureAlert = [UIAlertController alertControllerWithTitle:failureTitle
message:failureMessage
preferredStyle:UIAlertControllerStyleAlert];
UIAlertAction *failureCancelAction = [UIAlertAction actionWithTitle:[CommonStrings cancelButton]
style:UIAlertActionStyleCancel
handler:^(UIAlertAction *_Nonnull action) {
[self.shareViewDelegate shareViewWasCancelled];
}];
[failureAlert addAction:failureCancelAction];
if (untrustedRecipientId.length > 0) {
UIAlertAction *confirmAction =
[UIAlertAction actionWithTitle:[SafetyNumberStrings confirmSendButton]
style:UIAlertActionStyleDefault
handler:^(UIAlertAction *action) {
[self confirmIdentityAndResendMessage:message
recipientId:untrustedRecipientId
fromViewController:fromViewController];
}];
[failureAlert addAction:confirmAction];
} else {
// This shouldn't happen, but if it does we won't offer the user the ability to confirm.
// They may have to return to the main app to accept the identity change.
OWSFail(@"%@ Untrusted recipient error is missing recipient id.", self.logTag);
}
[fromViewController presentViewController:failureAlert animated:YES completion:nil];
} else {
// Non-identity failure, e.g. network offline, rate limit
UIAlertController *failureAlert = [UIAlertController alertControllerWithTitle:failureTitle
message:error.localizedDescription
preferredStyle:UIAlertControllerStyleAlert];
UIAlertAction *failureCancelAction = [UIAlertAction actionWithTitle:[CommonStrings cancelButton]
style:UIAlertActionStyleCancel
handler:^(UIAlertAction *_Nonnull action) {
[self.shareViewDelegate shareViewWasCancelled];
}];
[failureAlert addAction:failureCancelAction];
UIAlertAction *retryAction =
[UIAlertAction actionWithTitle:[CommonStrings retryButton]
style:UIAlertActionStyleDefault
handler:^(UIAlertAction *action) {
[self resendMessage:message fromViewController:fromViewController];
}];
[failureAlert addAction:retryAction];
[fromViewController presentViewController:failureAlert animated:YES completion:nil];
}
}
- (void)confirmIdentityAndResendMessage:(TSOutgoingMessage *)message
recipientId:(NSString *)recipientId
fromViewController:(UIViewController *)fromViewController
{
AssertIsOnMainThread();
OWSAssert(message);
OWSAssert(recipientId.length > 0);
OWSAssert(fromViewController);
DDLogDebug(@"%@ Confirming identity for recipient: %@", self.logTag, recipientId);
dispatch_async([OWSDispatch sessionStoreQueue], ^(void) {
OWSVerificationState verificationState =
[[OWSIdentityManager sharedManager] verificationStateForRecipientId:recipientId];
switch (verificationState) {
case OWSVerificationStateVerified: {
OWSFail(@"%@ Shouldn't need to confirm identity if it was already verified", self.logTag);
break;
}
case OWSVerificationStateDefault: {
// If we learned of a changed SN during send, then we've already recorded the new identity
// and there's nothing else we need to do for the resend to succeed.
// We don't want to redundantly set status to "default" because we would create a
// "You marked Alice as unverified" notice, which wouldn't make sense if Alice was never
// marked as "Verified".
DDLogInfo(@"%@ recipient has acceptable verification status. Next send will succeed.", self.logTag);
break;
}
case OWSVerificationStateNoLongerVerified: {
DDLogInfo(@"%@ marked recipient: %@ as default verification status.", self.logTag, recipientId);
NSData *identityKey = [[OWSIdentityManager sharedManager] identityKeyForRecipientId:recipientId];
OWSAssert(identityKey);
[[OWSIdentityManager sharedManager] setVerificationState:OWSVerificationStateDefault
identityKey:identityKey
recipientId:recipientId
isUserInitiatedChange:YES];
break;
}
}
dispatch_async(dispatch_get_main_queue(), ^(void) {
[self resendMessage:message fromViewController:fromViewController];
});
});
}
- (void)resendMessage:(TSOutgoingMessage *)message fromViewController:(UIViewController *)fromViewController
{
AssertIsOnMainThread();
OWSAssert(message);
OWSAssert(fromViewController);
NSString *progressTitle = NSLocalizedString(@"SHARE_EXTENSION_SENDING_IN_PROGRESS_TITLE", @"Alert title");
UIAlertController *progressAlert = [UIAlertController alertControllerWithTitle:progressTitle
message:nil
preferredStyle:UIAlertControllerStyleAlert];
UIAlertAction *progressCancelAction = [UIAlertAction actionWithTitle:[CommonStrings cancelButton]
style:UIAlertActionStyleCancel
handler:^(UIAlertAction *_Nonnull action) {
[self.shareViewDelegate shareViewWasCancelled];
}];
[progressAlert addAction:progressCancelAction];
[fromViewController
presentViewController:progressAlert
animated:YES
completion:^(void) {
[self.messageSender enqueueMessage:message
success:^(void) {
DDLogInfo(@"%@ Resending attachment succeeded.", self.logTag);
dispatch_async(dispatch_get_main_queue(), ^(void) {
[self.shareViewDelegate shareViewWasCompleted];
});
}
failure:^(NSError *error) {
dispatch_async(dispatch_get_main_queue(), ^(void) {
[fromViewController
dismissViewControllerAnimated:YES
completion:^(void) {
DDLogInfo(@"%@ Sending attachment failed with error: %@",
self.logTag,
error);
[self showSendFailureAlertWithError:error
message:message
fromViewController:fromViewController];
}];
});
}];
}];
}
- (void)attachmentUploadProgress:(NSNotification *)notification

View File

@ -861,7 +861,7 @@ NSString *const OWSMessageSenderRateLimitedException = @"RateLimitedException";
NSString *localizedErrorDescription =
[NSString stringWithFormat:localizedErrorDescriptionFormat,
[self.contactsManager displayNameForPhoneIdentifier:recipient.recipientId]];
NSError *error = OWSErrorWithCodeDescription(OWSErrorCodeUntrustedIdentityKey, localizedErrorDescription);
NSError *error = OWSErrorMakeUntrustedIdentityError(localizedErrorDescription, recipient.recipientId);
// Key will continue to be unaccepted, so no need to retry. It'll only cause us to hit the Pre-Key request
// rate limit
@ -869,7 +869,13 @@ NSString *const OWSMessageSenderRateLimitedException = @"RateLimitedException";
// Avoid the "Too many failures with this contact" error rate limiting.
[error setIsFatal:YES];
PreKeyBundle *newKeyBundle = exception.userInfo[TSInvalidPreKeyBundleKey];
PreKeyBundle *_Nullable newKeyBundle = exception.userInfo[TSInvalidPreKeyBundleKey];
if (newKeyBundle == nil) {
OWSProdFail([OWSAnalyticsEvents messageSenderErrorMissingNewPreKeyBundle]);
failureHandler(error);
return;
}
if (![newKeyBundle isKindOfClass:[PreKeyBundle class]]) {
OWSProdFail([OWSAnalyticsEvents messageSenderErrorUnexpectedKeyBundle]);
failureHandler(error);

View File

@ -10,6 +10,12 @@ NS_ASSUME_NONNULL_BEGIN
// The code between these markers is code-generated by:
// SignalServiceKit/Utilities/extract_analytics_event_names.py
// To add an event, insert your logging event as a string e.g.:
//
// OWSProdFail(@"messageSenderErrorMissingNewPreKeyBundle");
//
// Then run SignalServiceKit/Utilities/extract_analytics_event_names.py, which
// will extract the string into a named method in this class.
#pragma mark - Code Generation Marker
+ (NSString *)accountsErrorRegisterPushTokensFailed;
@ -96,6 +102,8 @@ NS_ASSUME_NONNULL_BEGIN
+ (NSString *)errorUpdateAttributesRequestFailed;
+ (NSString *)messageSenderErrorMissingNewPreKeyBundle;
+ (NSString *)messageManagerErrorCallMessageNoActionablePayload;
+ (NSString *)messageManagerErrorCorruptMessage;

View File

@ -222,6 +222,11 @@ NS_ASSUME_NONNULL_BEGIN
return @"error_update_attributes_request_failed";
}
+ (NSString *)messageSenderErrorMissingNewPreKeyBundle
{
return @"messageSenderErrorMissingNewPreKeyBundle";
}
+ (NSString *)messageManagerErrorCallMessageNoActionablePayload
{
return @"message_manager_error_call_message_no_actionable_payload";

View File

@ -13,7 +13,7 @@ typedef NS_ENUM(NSInteger, OWSErrorCode) {
OWSErrorCodeFailedToEncodeJson = 14,
OWSErrorCodeFailedToDecodeQR = 15,
OWSErrorCodePrivacyVerificationFailure = 20,
OWSErrorCodeUntrustedIdentityKey = 25,
OWSErrorCodeUntrustedIdentity = 25,
OWSErrorCodeFailedToSendOutgoingMessage = 30,
OWSErrorCodeFailedToDecryptMessage = 100,
OWSErrorCodeFailedToEncryptMessage = 110,
@ -29,7 +29,10 @@ typedef NS_ENUM(NSInteger, OWSErrorCode) {
OWSErrorCodeMessageDeletedBeforeSent = 777410,
};
extern NSString *const OWSErrorRecipientIdentifierKey;
extern NSError *OWSErrorWithCodeDescription(OWSErrorCode code, NSString *description);
extern NSError *OWSErrorMakeUntrustedIdentityError(NSString *description, NSString *recipientId);
extern NSError *OWSErrorMakeUnableToProcessServerResponseError(void);
extern NSError *OWSErrorMakeFailedToSendOutgoingMessageError(void);
extern NSError *OWSErrorMakeNoSuchSignalRecipientError(void);

View File

@ -7,6 +7,7 @@
NS_ASSUME_NONNULL_BEGIN
NSString *const OWSSignalServiceKitErrorDomain = @"OWSSignalServiceKitErrorDomain";
NSString *const OWSErrorRecipientIdentifierKey = @"OWSErrorKeyRecipientIdentifier";
NSError *OWSErrorWithCodeDescription(OWSErrorCode code, NSString *description)
{
@ -40,6 +41,14 @@ NSError *OWSErrorMakeAssertionError()
NSLocalizedString(@"ERROR_DESCRIPTION_UNKNOWN_ERROR", @"Worst case generic error message"));
}
NSError *OWSErrorMakeUntrustedIdentityError(NSString *description, NSString *recipientId)
{
return [NSError
errorWithDomain:OWSSignalServiceKitErrorDomain
code:OWSErrorCodeUntrustedIdentity
userInfo:@{ NSLocalizedDescriptionKey : description, OWSErrorRecipientIdentifierKey : recipientId }];
}
NSError *OWSErrorMakeMessageSendDisabledDueToPreKeyUpdateFailuresError()
{
return OWSErrorWithCodeDescription(OWSErrorCodeMessageSendDisabledDueToPreKeyUpdateFailures,