Only allow callback for identities that were not previously verified

// FREEBIE
This commit is contained in:
Michael Kirk 2017-06-06 18:59:38 -04:00
parent 1127553041
commit c8d547a08f
10 changed files with 187 additions and 115 deletions

View File

@ -36,8 +36,12 @@ class CallNotificationsAdapter: NSObject {
adaptee.presentMissedCall(call, callerName: callerName)
}
func presentRejectedCallWithIdentityChange(_ call: SignalCall, callerName: String) {
Logger.debug("\(TAG) in \(#function)")
adaptee.presentRejectedCallWithIdentityChange(call, callerName: callerName)
public func presentMissedCallBecauseOfNoLongerVerifiedIdentity(call: SignalCall, callerName: String) {
adaptee.presentMissedCallBecauseOfNoLongerVerifiedIdentity(call: call, callerName: callerName)
}
public func presentMissedCallBecauseOfNewIdentity(call: SignalCall, callerName: String) {
adaptee.presentMissedCallBecauseOfNewIdentity(call: call, callerName: callerName)
}
}

View File

@ -14,10 +14,10 @@ import UserNotifications
struct AppNotifications {
enum Category {
case missedCall,
rejectedCallFromUnseenIdentity
missedCallFromNoLongerVerifiedIdentity
// Don't forget to update this! We use it to register categories.
static let allValues = [ missedCall, rejectedCallFromUnseenIdentity ]
static let allValues = [ missedCall, missedCallFromNoLongerVerifiedIdentity ]
}
enum Action {
@ -39,9 +39,9 @@ struct AppNotifications {
intentIdentifiers: [],
options: [])
case .rejectedCallFromUnseenIdentity:
return UNNotificationCategory(identifier: "org.whispersystems.signal.AppNotifications.Category.rejectedCallFromUnseenIdentity",
actions: [ action(.confirmIdentityAndCallBack), action(.showThread) ],
case .missedCallFromNoLongerVerifiedIdentity:
return UNNotificationCategory(identifier: "org.whispersystems.signal.AppNotifications.Category.missedCallFromNoLongerVerifiedIdentity",
actions: [ action(.showThread) ],
intentIdentifiers: [],
options: [])
}
@ -118,7 +118,7 @@ class UserNotificationsAdaptee: NSObject, OWSCallNotificationsAdaptee, UNUserNot
let notificationBody = { () -> String in
switch previewType {
case .noNameNoPreview:
return CallStrings.missedCallNotificationBody
return CallStrings.missedCallNotificationBodyWithoutCallerName
case .nameNoPreview, .namePreview:
return (Environment.getCurrent().preferences.isCallKitPrivacyEnabled()
? CallStrings.missedCallNotificationBodyWithoutCallerName
@ -134,7 +134,7 @@ class UserNotificationsAdaptee: NSObject, OWSCallNotificationsAdaptee, UNUserNot
center.add(request)
}
func presentRejectedCallWithIdentityChange(_ call: SignalCall, callerName: String) {
public func presentMissedCallBecauseOfNoLongerVerifiedIdentity(call: SignalCall, callerName: String) {
Logger.debug("\(TAG) \(#function)")
let content = UNMutableNotificationContent()
@ -144,16 +144,42 @@ class UserNotificationsAdaptee: NSObject, OWSCallNotificationsAdaptee, UNUserNot
let notificationBody = { () -> String in
switch previewType {
case .noNameNoPreview:
return CallStrings.rejectedCallWithIdentityChangeNotificationBody
return CallStrings.missedCallWithIdentityChangeNotificationBodyWithoutCallerName
case .nameNoPreview, .namePreview:
return (Environment.getCurrent().preferences.isCallKitPrivacyEnabled()
? CallStrings.rejectedCallWithIdentityChangeNotificationBodyWithoutCallerName
: String(format: CallStrings.rejectedCallWithIdentityChangeNotificationBodyWithCallerName, callerName))
? CallStrings.missedCallWithIdentityChangeNotificationBodyWithoutCallerName
: String(format: CallStrings.missedCallWithIdentityChangeNotificationBodyWithCallerName, callerName))
}}()
content.body = notificationBody
content.sound = UNNotificationSound.default()
content.categoryIdentifier = AppNotifications.category(.rejectedCallFromUnseenIdentity).identifier
content.categoryIdentifier = AppNotifications.category(.missedCallFromNoLongerVerifiedIdentity).identifier
let request = UNNotificationRequest.init(identifier: call.localId.uuidString, content: content, trigger: nil)
center.add(request)
}
public func presentMissedCallBecauseOfNewIdentity(call: SignalCall, callerName: String) {
Logger.debug("\(TAG) \(#function)")
let content = UNMutableNotificationContent()
// TODO group by thread identifier
// content.threadIdentifier = threadId
let notificationBody = { () -> String in
switch previewType {
case .noNameNoPreview:
return CallStrings.missedCallWithIdentityChangeNotificationBodyWithoutCallerName
case .nameNoPreview, .namePreview:
return (Environment.getCurrent().preferences.isCallKitPrivacyEnabled()
? CallStrings.missedCallWithIdentityChangeNotificationBodyWithoutCallerName
: String(format: CallStrings.missedCallWithIdentityChangeNotificationBodyWithCallerName, callerName))
}}()
content.body = notificationBody
content.sound = UNNotificationSound.default()
content.categoryIdentifier = AppNotifications.category(.missedCall).identifier
let request = UNNotificationRequest.init(identifier: call.localId.uuidString, content: content, trigger: nil)

View File

@ -111,46 +111,61 @@ NS_ASSUME_NONNULL_BEGIN
// give a little delay.
uint64_t notificationDelay = 5;
[contents
addSection:[OWSTableSection
sectionWithTitle:[NSString stringWithFormat:@"Call Notifications (%llu second delay)",
notificationDelay]
items:@[
[OWSTableItem itemWithTitle:@"Missed Call"
actionBlock:^{
SignalCall *call = [SignalCall
incomingCallWithLocalId:[NSUUID new]
remotePhoneNumber:thread.contactIdentifier
signalingId:0];
addSection:
[OWSTableSection
sectionWithTitle:[NSString
stringWithFormat:@"Call Notifications (%llu second delay)", notificationDelay]
items:@[
[OWSTableItem itemWithTitle:@"Missed Call"
actionBlock:^{
SignalCall *call =
[SignalCall incomingCallWithLocalId:[NSUUID new]
remotePhoneNumber:thread.contactIdentifier
signalingId:0];
dispatch_after(
dispatch_time(DISPATCH_TIME_NOW,
(int64_t)(notificationDelay * NSEC_PER_SEC)),
dispatch_get_main_queue(),
^{
[[Environment getCurrent]
.callService.notificationsAdapter
presentMissedCall:call
callerName:thread.name];
});
}],
[OWSTableItem
itemWithTitle:@"Rejected Call with Unseen Safety Number"
actionBlock:^{
SignalCall *call =
[SignalCall incomingCallWithLocalId:[NSUUID new]
remotePhoneNumber:thread.contactIdentifier
signalingId:0];
dispatch_after(dispatch_time(DISPATCH_TIME_NOW,
(int64_t)(notificationDelay * NSEC_PER_SEC)),
dispatch_get_main_queue(),
^{
[[Environment getCurrent].callService.notificationsAdapter
presentMissedCall:call
callerName:thread.name];
});
}],
[OWSTableItem
itemWithTitle:@"Rejected Call with New Safety Number"
actionBlock:^{
SignalCall *call = [SignalCall incomingCallWithLocalId:[NSUUID new]
remotePhoneNumber:thread.contactIdentifier
signalingId:0];
dispatch_after(dispatch_time(DISPATCH_TIME_NOW,
(int64_t)(notificationDelay * NSEC_PER_SEC)),
dispatch_get_main_queue(),
^{
[[Environment getCurrent].callService.notificationsAdapter
presentRejectedCallWithIdentityChange:call
callerName:thread.name];
});
}],
]]];
dispatch_after(dispatch_time(DISPATCH_TIME_NOW,
(int64_t)(notificationDelay * NSEC_PER_SEC)),
dispatch_get_main_queue(),
^{
[[Environment getCurrent].callService.notificationsAdapter
presentMissedCallBecauseOfNewIdentityWithCall:call
callerName:thread.name];
});
}],
[OWSTableItem
itemWithTitle:@"Rejected Call with No Longer Verified Safety Number"
actionBlock:^{
SignalCall *call = [SignalCall incomingCallWithLocalId:[NSUUID new]
remotePhoneNumber:thread.contactIdentifier
signalingId:0];
dispatch_after(dispatch_time(DISPATCH_TIME_NOW,
(int64_t)(notificationDelay * NSEC_PER_SEC)),
dispatch_get_main_queue(),
^{
[[Environment getCurrent].callService.notificationsAdapter
presentMissedCallBecauseOfNoLongerVerifiedIdentityWithCall:call
callerName:
thread.name];
});
}],
]]];
viewController.contents = contents;
[viewController presentFromViewController:fromViewController];

View File

@ -34,12 +34,12 @@ class SafetyNumberConfirmationAlert: NSObject {
*/
public func presentIfNecessary(recipientIds: [String], confirmationText: String, completion: @escaping (Bool) -> Void) -> Bool {
guard let noLongerVerifiedIdentity = noLongerVerifiedIdentity(recipientIds: recipientIds) else {
guard let untrustedIdentity = untrustedIdentityForSending(recipientIds: recipientIds) else {
// No identities to confirm, no alert to present.
return false
}
let displayName = contactsManager.displayName(forPhoneIdentifier: noLongerVerifiedIdentity.recipientId)
let displayName = contactsManager.displayName(forPhoneIdentifier: untrustedIdentity.recipientId)
let titleFormat = NSLocalizedString("CONFIRM_SENDING_TO_CHANGED_IDENTITY_TITLE_FORMAT",
comment: "Action sheet title presented when a users's SN have recently changed. Embeds {{contact's name or phone number}}")
@ -52,10 +52,10 @@ class SafetyNumberConfirmationAlert: NSObject {
let actionSheetController = UIAlertController(title: title, message:body, preferredStyle: .actionSheet)
let confirmAction = UIAlertAction(title: confirmationText, style: .default) { _ in
Logger.info("\(self.TAG) Confirmed identity: \(noLongerVerifiedIdentity)")
Logger.info("\(self.TAG) Confirmed identity: \(untrustedIdentity)")
OWSDispatch.sessionStoreQueue().async {
OWSIdentityManager.shared().setVerificationState(.default, identityKey: noLongerVerifiedIdentity.identityKey, recipientId: noLongerVerifiedIdentity.recipientId, sendSyncMessage: true)
OWSIdentityManager.shared().setVerificationState(.default, identityKey: untrustedIdentity.identityKey, recipientId: untrustedIdentity.recipientId, sendSyncMessage: true)
DispatchQueue.main.async {
completion(true)
}
@ -64,10 +64,10 @@ class SafetyNumberConfirmationAlert: NSObject {
actionSheetController.addAction(confirmAction)
let showSafetyNumberAction = UIAlertAction(title: NSLocalizedString("VERIFY_PRIVACY", comment: "Action sheet item"), style: .default) { _ in
Logger.info("\(self.TAG) Opted to show Safety Number for identity: \(noLongerVerifiedIdentity)")
Logger.info("\(self.TAG) Opted to show Safety Number for identity: \(untrustedIdentity)")
self.presentSafetyNumberViewController(theirIdentityKey: noLongerVerifiedIdentity.identityKey,
theirRecipientId: noLongerVerifiedIdentity.recipientId,
self.presentSafetyNumberViewController(theirIdentityKey: untrustedIdentity.identityKey,
theirRecipientId: untrustedIdentity.recipientId,
theirDisplayName: displayName,
completion: { completion(false) })
@ -92,9 +92,9 @@ class SafetyNumberConfirmationAlert: NSObject {
UIApplication.shared.frontmostViewController?.present(fingerprintViewController, animated: true, completion: completion)
}
private func noLongerVerifiedIdentity(recipientIds: [String]) -> OWSRecipientIdentity? {
private func untrustedIdentityForSending(recipientIds: [String]) -> OWSRecipientIdentity? {
return recipientIds.flatMap {
OWSIdentityManager.shared().noLongerVerifiedIdentity(recipientId: $0)
OWSIdentityManager.shared().untrustedIdentityForSending(toRecipientId: $0)
}.first
}
}

View File

@ -470,9 +470,21 @@ protocol CallServiceObserver: class {
let newCall = SignalCall.incomingCall(localId: UUID(), remotePhoneNumber: thread.contactIdentifier(), signalingId: callId)
guard OWSIdentityManager.shared().isCurrentIdentityTrustedForSending(toRecipientId: thread.contactIdentifier()) else {
let untrustedIdentity = OWSIdentityManager.shared().untrustedIdentityForSending(toRecipientId: thread.contactIdentifier())
guard untrustedIdentity == nil else {
let callerName = self.contactsManager.displayName(forPhoneIdentifier: thread.contactIdentifier())
self.notificationsAdapter.presentRejectedCallWithIdentityChange(newCall, callerName: callerName)
switch(untrustedIdentity!.verificationState) {
case .verified:
assertionFailure("shouldn't have missed a call due to untrusted identity if the identity is verified")
self.notificationsAdapter.presentMissedCall(newCall, callerName: callerName)
case .default:
self.notificationsAdapter.presentMissedCallBecauseOfNewIdentity(call: newCall, callerName: callerName)
case .noLongerVerified:
self.notificationsAdapter.presentMissedCallBecauseOfNoLongerVerifiedIdentity(call: newCall, callerName: callerName)
}
return
}

View File

@ -4,6 +4,7 @@
NS_ASSUME_NONNULL_BEGIN
@class OWSRecipientIdentity;
@class SignalCall;
@protocol OWSCallNotificationsAdaptee <NSObject>
@ -12,10 +13,13 @@ NS_ASSUME_NONNULL_BEGIN
- (void)presentMissedCall:(SignalCall *)call callerName:(NSString *)callerName;
- (void)presentRejectedCallWithIdentityChange:(SignalCall *)call
- (void)presentMissedCallBecauseOfNewIdentity:(SignalCall *)call
callerName:(NSString *)callerName
NS_SWIFT_NAME(presentRejectedCallWithIdentityChange(_:callerName
:));
NS_SWIFT_NAME(presentMissedCallBecauseOfNewIdentity(call:callerName:));
- (void)presentMissedCallBecauseOfNoLongerVerifiedIdentity:(SignalCall *)call
callerName:(NSString *)callerName
NS_SWIFT_NAME(presentMissedCallBecauseOfNoLongerVerifiedIdentity(call:callerName:));
@end

View File

@ -96,7 +96,7 @@
NSString *alertMessage;
switch (self.notificationPreviewType) {
case NotificationNoNameNoPreview: {
alertMessage = [CallStrings missedCallNotificationBody];
alertMessage = [CallStrings missedCallNotificationBodyWithoutCallerName];
break;
}
case NotificationNameNoPreview:
@ -113,13 +113,15 @@
[self presentNotification:notification identifier:localCallId];
}
- (void)presentRejectedCallWithIdentityChange:(SignalCall *)call callerName:(NSString *)callerName
- (void)presentMissedCallBecauseOfNewIdentity:(SignalCall *)call callerName:(NSString *)callerName
{
TSContactThread *thread = [TSContactThread getOrCreateThreadWithContactId:call.remotePhoneNumber];
OWSAssert(thread != nil);
UILocalNotification *notification = [UILocalNotification new];
notification.category = PushManagerCategoriesRejectedCallFromIdentityChange;
// Use category which allows call back
notification.category = PushManagerCategoriesMissedCall;
NSString *localCallId = call.localId.UUIDString;
notification.userInfo = @{
PushManagerUserInfoKeysLocalCallId : localCallId,
@ -130,16 +132,53 @@
NSString *alertMessage;
switch (self.notificationPreviewType) {
case NotificationNoNameNoPreview: {
alertMessage = [CallStrings rejectedCallWithIdentityChangeNotificationBody];
alertMessage = [CallStrings missedCallWithIdentityChangeNotificationBodyWithoutCallerName];
break;
}
case NotificationNameNoPreview:
case NotificationNamePreview: {
alertMessage = (([UIDevice currentDevice].supportsCallKit &&
[[Environment getCurrent].preferences isCallKitPrivacyEnabled])
? [CallStrings rejectedCallWithIdentityChangeNotificationBodyWithoutCallerName]
? [CallStrings missedCallWithIdentityChangeNotificationBodyWithoutCallerName]
: [NSString
stringWithFormat:[CallStrings rejectedCallWithIdentityChangeNotificationBodyWithCallerName],
stringWithFormat:[CallStrings missedCallWithIdentityChangeNotificationBodyWithCallerName],
callerName]);
break;
}
}
notification.alertBody = [NSString stringWithFormat:@"☎️ %@", alertMessage];
[self presentNotification:notification identifier:localCallId];
}
- (void)presentMissedCallBecauseOfNoLongerVerifiedIdentity:(SignalCall *)call callerName:(NSString *)callerName
{
TSContactThread *thread = [TSContactThread getOrCreateThreadWithContactId:call.remotePhoneNumber];
OWSAssert(thread != nil);
UILocalNotification *notification = [UILocalNotification new];
// Use category which does not allow call back
notification.category = PushManagerCategoriesMissedCallFromNoLongerVerifiedIdentity;
NSString *localCallId = call.localId.UUIDString;
notification.userInfo = @{
PushManagerUserInfoKeysLocalCallId : localCallId,
PushManagerUserInfoKeysCallBackSignalRecipientId : call.remotePhoneNumber,
Signal_Thread_UserInfo_Key : thread.uniqueId
};
NSString *alertMessage;
switch (self.notificationPreviewType) {
case NotificationNoNameNoPreview: {
alertMessage = [CallStrings missedCallWithIdentityChangeNotificationBodyWithoutCallerName];
break;
}
case NotificationNameNoPreview:
case NotificationNamePreview: {
alertMessage = (([UIDevice currentDevice].supportsCallKit &&
[[Environment getCurrent].preferences isCallKitPrivacyEnabled])
? [CallStrings missedCallWithIdentityChangeNotificationBodyWithoutCallerName]
: [NSString
stringWithFormat:[CallStrings missedCallWithIdentityChangeNotificationBodyWithCallerName],
callerName]);
break;
}

View File

@ -22,12 +22,11 @@ extern NSString *const Signal_Message_MarkAsRead_Identifier;
extern NSString *const PushManagerCategoriesIncomingCall;
extern NSString *const PushManagerCategoriesMissedCall;
extern NSString *const PushManagerCategoriesRejectedCallFromIdentityChange;
extern NSString *const PushManagerCategoriesMissedCallFromNoLongerVerifiedIdentity;
extern NSString *const PushManagerActionsAcceptCall;
extern NSString *const PushManagerActionsDeclineCall;
extern NSString *const PushManagerActionsCallBack;
extern NSString *const PushManagerActionsIgnoreIdentityChangeAndCallBack;
extern NSString *const PushManagerActionsShowThread;
extern NSString *const PushManagerUserInfoKeysCallBackSignalRecipientId;

View File

@ -209,25 +209,6 @@ NSString *const Signal_Message_MarkAsRead_Identifier = @"Signal_Message_MarkAsRe
[self.callUIAdapter startAndShowOutgoingCallWithRecipientId:recipientId];
completionHandler();
} else if ([identifier isEqualToString:PushManagerActionsIgnoreIdentityChangeAndCallBack]) {
NSString *recipientId = notification.userInfo[PushManagerUserInfoKeysCallBackSignalRecipientId];
if (!recipientId) {
DDLogError(@"%@ missing call back id", self.tag);
return;
}
NSData *currentIdentityKey = [[OWSIdentityManager sharedManager] identityKeyForRecipientId:recipientId];
if (currentIdentityKey.length <= 0) {
OWSFail(@"%@ currentIdentityKey unexpectedly empty for recipient: %@", self.tag, recipientId);
completionHandler();
return;
}
[[OWSIdentityManager sharedManager] setVerificationState:OWSVerificationStateDefault
identityKey:currentIdentityKey
recipientId:recipientId
sendSyncMessage:YES];
[self.callUIAdapter startAndShowOutgoingCallWithRecipientId:recipientId];
completionHandler();
} else if ([identifier isEqualToString:PushManagerActionsShowThread]) {
NSString *threadId = notification.userInfo[Signal_Thread_UserInfo_Key];
[Environment messageThreadId:threadId];
@ -364,8 +345,8 @@ NSString *const Signal_Message_MarkAsRead_Identifier = @"Signal_Message_MarkAsRe
NSString *const PushManagerCategoriesIncomingCall = @"PushManagerCategoriesIncomingCall";
NSString *const PushManagerCategoriesMissedCall = @"PushManagerCategoriesMissedCall";
NSString *const PushManagerCategoriesRejectedCallFromIdentityChange =
@"PushManagerCategoriesRejectedCallFromIdentityChange";
NSString *const PushManagerCategoriesMissedCallFromNoLongerVerifiedIdentity =
@"PushManagerCategoriesMissedCallFromNoLongerVerifiedIdentity";
NSString *const PushManagerActionsAcceptCall = @"PushManagerActionsAcceptCall";
NSString *const PushManagerActionsDeclineCall = @"PushManagerActionsDeclineCall";
@ -418,14 +399,8 @@ NSString *const PushManagerUserInfoKeysCallBackSignalRecipientId = @"PushManager
return missedCallCategory;
}
- (UIUserNotificationCategory *)signalRejectedCallWithUnseenIdentityChangeCategory
- (UIUserNotificationCategory *)signalMissedCallWithNoLongerVerifiedIdentityChangeCategory
{
UIMutableUserNotificationAction *confirmAndCallBackAction = [UIMutableUserNotificationAction new];
confirmAndCallBackAction.identifier = PushManagerActionsIgnoreIdentityChangeAndCallBack;
confirmAndCallBackAction.title = [CallStrings confirmIdentityAndCallBackButtonTitle];
confirmAndCallBackAction.activationMode = UIUserNotificationActivationModeForeground;
confirmAndCallBackAction.destructive = NO;
confirmAndCallBackAction.authenticationRequired = YES;
UIMutableUserNotificationAction *showThreadAction = [UIMutableUserNotificationAction new];
showThreadAction.identifier = PushManagerActionsShowThread;
@ -435,11 +410,9 @@ NSString *const PushManagerUserInfoKeysCallBackSignalRecipientId = @"PushManager
showThreadAction.authenticationRequired = YES;
UIMutableUserNotificationCategory *rejectedCallCategory = [UIMutableUserNotificationCategory new];
rejectedCallCategory.identifier = PushManagerCategoriesRejectedCallFromIdentityChange;
[rejectedCallCategory setActions:@[ confirmAndCallBackAction, showThreadAction ]
forContext:UIUserNotificationActionContextMinimal];
[rejectedCallCategory setActions:@[ confirmAndCallBackAction, showThreadAction ]
forContext:UIUserNotificationActionContextDefault];
rejectedCallCategory.identifier = PushManagerCategoriesMissedCallFromNoLongerVerifiedIdentity;
[rejectedCallCategory setActions:@[ showThreadAction ] forContext:UIUserNotificationActionContextMinimal];
[rejectedCallCategory setActions:@[ showThreadAction ] forContext:UIUserNotificationActionContextDefault];
return rejectedCallCategory;
}
@ -460,13 +433,13 @@ NSString *const PushManagerUserInfoKeysCallBackSignalRecipientId = @"PushManager
- (void)validateUserNotificationSettings
{
UIUserNotificationSettings *settings =
[UIUserNotificationSettings settingsForTypes:(UIUserNotificationType)[self allNotificationTypes]
categories:[NSSet setWithObjects:[self fullNewMessageNotificationCategory],
[self signalIncomingCallCategory],
[self signalMissedCallCategory],
[self signalRejectedCallWithUnseenIdentityChangeCategory],
nil]];
UIUserNotificationSettings *settings = [UIUserNotificationSettings
settingsForTypes:(UIUserNotificationType)[self allNotificationTypes]
categories:[NSSet setWithObjects:[self fullNewMessageNotificationCategory],
[self signalIncomingCallCategory],
[self signalMissedCallCategory],
[self signalMissedCallWithNoLongerVerifiedIdentityChangeCategory],
nil]];
[UIApplication.sharedApplication registerUserNotificationSettings:settings];
}

View File

@ -743,7 +743,7 @@
"MISSED_CALL" = "Missed call";
/* notification title. Embeds {{caller's name or phone number}} */
"MISSED_CALL_WITH_CHANGED_IDENTITY_BODY_WITH_CALLER_NAME" = "Missed call because the caller's safety number changed.";
"MISSED_CALL_WITH_CHANGED_IDENTITY_BODY_WITH_CALLER_NAME" = "Missed call from %@ because their safety number changed.";
/* notification title */
"MISSED_CALL_WITH_CHANGED_IDENTITY_BODY_WITHOUT_CALLER_NAME" = "Missed call because the caller's safety number changed.";