diff --git a/Podfile.lock b/Podfile.lock index 709615233a..e421ac97e9 100644 --- a/Podfile.lock +++ b/Podfile.lock @@ -136,7 +136,7 @@ CHECKOUT OPTIONS: :commit: 7054e4b13ee5bcd6d524adb6dc9a726e8c466308 :git: https://github.com/WhisperSystems/JSQMessagesViewController.git SignalServiceKit: - :commit: 43d1aa49dc869486cdba8546b56e716beae5c1d0 + :commit: d475c58348a0a8c4ed9b0fcdbe352cd87e8ce269 :git: https://github.com/WhisperSystems/SignalServiceKit.git SocketRocket: :commit: 877ac7438be3ad0b45ef5ca3969574e4b97112bf diff --git a/Signal.xcodeproj/project.pbxproj b/Signal.xcodeproj/project.pbxproj index 1720ae466a..55b226498f 100644 --- a/Signal.xcodeproj/project.pbxproj +++ b/Signal.xcodeproj/project.pbxproj @@ -154,7 +154,6 @@ 458E38371D668EBF0094BD24 /* OWSDeviceProvisioningURLParser.m in Sources */ = {isa = PBXBuildFile; fileRef = 458E38361D668EBF0094BD24 /* OWSDeviceProvisioningURLParser.m */; }; 458E383A1D6699FA0094BD24 /* OWSDeviceProvisioningURLParserTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 458E38391D6699FA0094BD24 /* OWSDeviceProvisioningURLParserTest.m */; }; 459311FC1D75C948008DD4F0 /* OWSDeviceTableViewCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 459311FB1D75C948008DD4F0 /* OWSDeviceTableViewCell.m */; }; - 459B1C671ED480BB00506A04 /* MarkIdentityAsSeenJob.swift in Sources */ = {isa = PBXBuildFile; fileRef = 459B1C661ED480BB00506A04 /* MarkIdentityAsSeenJob.swift */; }; 45A6DAD61EBBF85500893231 /* ReminderView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 45A6DAD51EBBF85500893231 /* ReminderView.swift */; }; 45A6DAD71EBBF85500893231 /* ReminderView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 45A6DAD51EBBF85500893231 /* ReminderView.swift */; }; 45AE48511E0732D6004D96C2 /* TurnServerInfo.swift in Sources */ = {isa = PBXBuildFile; fileRef = 45AE48501E0732D6004D96C2 /* TurnServerInfo.swift */; }; @@ -577,7 +576,6 @@ 459311FB1D75C948008DD4F0 /* OWSDeviceTableViewCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWSDeviceTableViewCell.m; sourceTree = ""; }; 4597E94E1D8313C100040CDE /* sq */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = sq; path = translations/sq.lproj/Localizable.strings; sourceTree = ""; }; 4597E94F1D8313CB00040CDE /* bg */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = bg; path = translations/bg.lproj/Localizable.strings; sourceTree = ""; }; - 459B1C661ED480BB00506A04 /* MarkIdentityAsSeenJob.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = MarkIdentityAsSeenJob.swift; path = Jobs/MarkIdentityAsSeenJob.swift; sourceTree = ""; }; 45A6DAD51EBBF85500893231 /* ReminderView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ReminderView.swift; sourceTree = ""; }; 45AE48501E0732D6004D96C2 /* TurnServerInfo.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TurnServerInfo.swift; sourceTree = ""; }; 45B201741DAECBFD00C461E0 /* Signal-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Signal-Bridging-Header.h"; sourceTree = ""; }; @@ -1163,7 +1161,6 @@ 451DE9FC1DC1A28200810E42 /* SyncPushTokensJob.swift */, 45D231761DC7E8F10034FA89 /* SessionResetJob.swift */, 452ECA4C1E087E7200E2F016 /* MessageFetcherJob.swift */, - 459B1C661ED480BB00506A04 /* MarkIdentityAsSeenJob.swift */, 4585C4651ED5DF7A00896AEA /* ProfileFetcherJob.swift */, ); name = Jobs; @@ -2126,7 +2123,6 @@ 45C0DC1E1E69011F00E04C47 /* UIStoryboard+OWS.swift in Sources */, 34F3089F1ECA580B00BB7697 /* OWSUnreadIndicatorCell.m in Sources */, 34B3F8861E8DF1700035BE1A /* NotificationSettingsOptionsViewController.m in Sources */, - 459B1C671ED480BB00506A04 /* MarkIdentityAsSeenJob.swift in Sources */, 452ECA4D1E087E7200E2F016 /* MessageFetcherJob.swift in Sources */, 452EA0971EA662330078744B /* AttachmentPointerAdapter.swift in Sources */, 34DFCB851E8E04B500053165 /* AddToBlockListViewController.m in Sources */, diff --git a/Signal/src/Jobs/MarkIdentityAsSeenJob.swift b/Signal/src/Jobs/MarkIdentityAsSeenJob.swift deleted file mode 100644 index 329f0b78bb..0000000000 --- a/Signal/src/Jobs/MarkIdentityAsSeenJob.swift +++ /dev/null @@ -1,43 +0,0 @@ -// -// Copyright (c) 2017 Open Whisper Systems. All rights reserved. -// - -import Foundation - -@objc -class MarkIdentityAsSeenJob: NSObject { - let TAG = "[MarkIdentityAsSeenJob]" - - private let recipientIds: [String] - - public class func run(thread: TSThread) { - let recipientIds = thread.recipientIdentifiers - - MarkIdentityAsSeenJob(recipientIds: recipientIds).run() - } - - public class func run(recipientId: String) { - MarkIdentityAsSeenJob(recipientIds: [recipientId]).run() - } - - init(recipientIds: [String]) { - self.recipientIds = recipientIds - } - - public func run() { - for recipientId in self.recipientIds { - markAsSeenIfNecessary(recipientId: recipientId) - } - } - - private func markAsSeenIfNecessary(recipientId: String) { - guard let identity = OWSRecipientIdentity.fetch(uniqueId: recipientId) else { - Logger.verbose("\(self.TAG) no existing identity for recipient: \(recipientId). No messages with them yet?") - return - } - if !identity.wasSeen { - Logger.info("\(self.TAG) marking identity as seen for recipient: \(recipientId)") - identity.updateAsSeen() - } - } -} diff --git a/Signal/src/ProfileFetcherJob.swift b/Signal/src/ProfileFetcherJob.swift index ad1c1009e0..f80ddb5174 100644 --- a/Signal/src/ProfileFetcherJob.swift +++ b/Signal/src/ProfileFetcherJob.swift @@ -62,12 +62,12 @@ class ProfileFetcherJob: NSObject { private func verifyIdentityUpToDateAsync(recipientId: String, latestIdentityKey: Data) { OWSDispatch.sessionStoreQueue().async { - if self.storageManager.identityKey(forRecipientId: recipientId) == nil { + if OWSIdentityManager.shared().identityKey(forRecipientId: recipientId) == nil { // first time use, do nothing, since there's no change. return } - if self.storageManager.saveRemoteIdentity(latestIdentityKey, recipientId: recipientId) { + if OWSIdentityManager.shared().saveRemoteIdentity(latestIdentityKey, recipientId: recipientId) { Logger.info("\(self.TAG) updated identity key in fetched profile for recipient: \(recipientId)") self.storageManager.deleteAllSessions(forContact: recipientId) } else { diff --git a/Signal/src/Signal-Bridging-Header.h b/Signal/src/Signal-Bridging-Header.h index 5a2fad7497..6aa08aaa70 100644 --- a/Signal/src/Signal-Bridging-Header.h +++ b/Signal/src/Signal-Bridging-Header.h @@ -52,13 +52,14 @@ #import #import #import +#import +#import #import #import +#import #import #import #import -#import -#import #import #import #import @@ -77,7 +78,6 @@ #import #import #import -#import #import #import #import diff --git a/Signal/src/UserInterface/Notifications/CallNotificationsAdapter.swift b/Signal/src/UserInterface/Notifications/CallNotificationsAdapter.swift index 8d0d95a40c..235592126b 100644 --- a/Signal/src/UserInterface/Notifications/CallNotificationsAdapter.swift +++ b/Signal/src/UserInterface/Notifications/CallNotificationsAdapter.swift @@ -36,8 +36,12 @@ class CallNotificationsAdapter: NSObject { adaptee.presentMissedCall(call, callerName: callerName) } - func presentRejectedCallWithUnseenIdentityChange(_ call: SignalCall, callerName: String) { - Logger.debug("\(TAG) in \(#function)") - adaptee.presentRejectedCallWithUnseenIdentityChange(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) + } + } diff --git a/Signal/src/UserInterface/Notifications/UserNotificationsAdaptee.swift b/Signal/src/UserInterface/Notifications/UserNotificationsAdaptee.swift index 676a471792..764bb8552c 100644 --- a/Signal/src/UserInterface/Notifications/UserNotificationsAdaptee.swift +++ b/Signal/src/UserInterface/Notifications/UserNotificationsAdaptee.swift @@ -14,16 +14,15 @@ 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 { case callBack, - showThread, - confirmIdentityAndCallBack + showThread } static var allCategories: Set { @@ -39,9 +38,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: []) } @@ -57,10 +56,6 @@ struct AppNotifications { return UNNotificationAction(identifier: "org.whispersystems.signal.AppNotifications.Action.showThread", title: CallStrings.showThreadButtonTitle, options: .authenticationRequired) - case .confirmIdentityAndCallBack: - return UNNotificationAction(identifier: "org.whispersystems.signal.AppNotifications.Action.confirmIdentityAndCallBack", - title: CallStrings.confirmIdentityAndCallBackButtonTitle, - options: .authenticationRequired) } } } @@ -118,7 +113,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 +129,7 @@ class UserNotificationsAdaptee: NSObject, OWSCallNotificationsAdaptee, UNUserNot center.add(request) } - func presentRejectedCallWithUnseenIdentityChange(_ call: SignalCall, callerName: String) { + public func presentMissedCallBecauseOfNoLongerVerifiedIdentity(call: SignalCall, callerName: String) { Logger.debug("\(TAG) \(#function)") let content = UNMutableNotificationContent() @@ -144,16 +139,42 @@ class UserNotificationsAdaptee: NSObject, OWSCallNotificationsAdaptee, UNUserNot let notificationBody = { () -> String in switch previewType { case .noNameNoPreview: - return CallStrings.rejectedCallWithUnseenIdentityChangeNotificationBody + return CallStrings.missedCallWithIdentityChangeNotificationBodyWithoutCallerName case .nameNoPreview, .namePreview: return (Environment.getCurrent().preferences.isCallKitPrivacyEnabled() - ? CallStrings.rejectedCallWithUnseenIdentityChangeNotificationBodyWithoutCallerName - : String(format: CallStrings.rejectedCallWithUnseenIdentityChangeNotificationBodyWithCallerName, 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) diff --git a/Signal/src/UserInterface/Strings.swift b/Signal/src/UserInterface/Strings.swift index 60ef70c61d..b457b18baf 100644 --- a/Signal/src/UserInterface/Strings.swift +++ b/Signal/src/UserInterface/Strings.swift @@ -13,22 +13,19 @@ import Foundation static let confirmAndCallButtonTitle = NSLocalizedString("SAFETY_NUMBER_CHANGED_CONFIRM_CALL_ACTION", comment: "alert button text to confirm placing an outgoing call after the recipients Safety Number has changed.") - // MARK: Notification actions - static let callBackButtonTitle = NSLocalizedString("CALLBACK_BUTTON_TITLE", comment: "notification action") - static let confirmIdentityAndCallBackButtonTitle = NSLocalizedString("CONFIRM_IDENTITY_AND_CALLBACK_BUTTON_TITLE", comment: "notification action, confirming that it's OK to proceed calling after a caller's Safety Number has changed") - static let showThreadButtonTitle = NSLocalizedString("SHOW_THREAD_BUTTON_TITLE", comment: "notification action") - - // MARK: Missed Call Notification - static let missedCallNotificationBody = NSLocalizedString("MISSED_CALL", comment: "notification title") - static let missedCallNotificationBodyWithCallerName = NSLocalizedString("MSGVIEW_MISSED_CALL_WITH_NAME", comment: "notification title. Embeds {{Caller's Name}}") - static let missedCallNotificationBodyWithoutCallerName = NSLocalizedString("MSGVIEW_MISSED_CALL_WITHOUT_NAME", comment: "notification title.") - - // MARK: Missed with Unseen identity Notification - static let rejectedCallWithUnseenIdentityChangeNotificationBody = NSLocalizedString("MISSED_CALL_WITH_UNSEEN_IDENTITY_BODY", comment: "notification action") - static let rejectedCallWithUnseenIdentityChangeNotificationBodyWithoutCallerName = NSLocalizedString("MISSED_CALL_WITH_UNSEEN_IDENTITY_BODY_WITHOUT_CALLER_NAME", comment: "notification action") - static let rejectedCallWithUnseenIdentityChangeNotificationBodyWithCallerName = NSLocalizedString("MISSED_CALL_WITH_UNSEEN_IDENTITY_BODY_WITH_CALLER_NAME", comment: "notification action") - static let callBackAlertTitle = NSLocalizedString("CALL_USER_ALERT_TITLE", comment: "Title for alert offering to call a user.") static let callBackAlertMessageFormat = NSLocalizedString("CALL_USER_ALERT_MESSAGE_FORMAT", comment: "Message format for alert offering to call a user. Embeds {{the user's display name or phone number}}.") static let callBackAlertCallButton = NSLocalizedString("CALL_USER_ALERT_CALL_BUTTON", comment: "Label for call button for alert offering to call a user.") + + // MARK: Notification actions + static let callBackButtonTitle = NSLocalizedString("CALLBACK_BUTTON_TITLE", comment: "notification action") + static let showThreadButtonTitle = NSLocalizedString("SHOW_THREAD_BUTTON_TITLE", comment: "notification action") + + // MARK: Missed Call Notification + static let missedCallNotificationBodyWithoutCallerName = NSLocalizedString("MISSED_CALL", comment: "notification title") + static let missedCallNotificationBodyWithCallerName = NSLocalizedString("MSGVIEW_MISSED_CALL_WITH_NAME", comment: "notification title. Embeds {{caller's name or phone number}}") + + // MARK: Missed with changed identity notification (for not previously verified identity) + static let missedCallWithIdentityChangeNotificationBodyWithoutCallerName = NSLocalizedString("MISSED_CALL_WITH_CHANGED_IDENTITY_BODY_WITHOUT_CALLER_NAME", comment: "notification title") + static let missedCallWithIdentityChangeNotificationBodyWithCallerName = NSLocalizedString("MISSED_CALL_WITH_CHANGED_IDENTITY_BODY_WITH_CALLER_NAME", comment: "notification title. Embeds {{caller's name or phone number}}") } diff --git a/Signal/src/ViewControllers/AddToGroupViewController.m b/Signal/src/ViewControllers/AddToGroupViewController.m index 2171408715..0a2e8e2dfa 100644 --- a/Signal/src/ViewControllers/AddToGroupViewController.m +++ b/Signal/src/ViewControllers/AddToGroupViewController.m @@ -73,7 +73,6 @@ NS_ASSUME_NONNULL_BEGIN @"button title to confirm adding a recipient to a group when their safety " @"number has recently changed") contactsManager:helper.contactsManager - verifySeen:YES completion:^(BOOL didConfirmIdentity) { if (didConfirmIdentity) { [weakSelf addToGroup:phoneNumber]; @@ -125,7 +124,6 @@ NS_ASSUME_NONNULL_BEGIN @"button title to confirm adding a recipient to a group when their safety " @"number has recently changed") contactsManager:helper.contactsManager - verifySeen:YES completion:^(BOOL didConfirmIdentity) { if (didConfirmIdentity) { [weakSelf addToGroup:signalAccount.recipientId]; diff --git a/Signal/src/ViewControllers/ConversationView/MessagesViewController.m b/Signal/src/ViewControllers/ConversationView/MessagesViewController.m index 68b38148a9..ce78559e06 100644 --- a/Signal/src/ViewControllers/ConversationView/MessagesViewController.m +++ b/Signal/src/ViewControllers/ConversationView/MessagesViewController.m @@ -834,7 +834,6 @@ typedef enum : NSUInteger { _callOnOpen = NO; } [self updateNavigationBarSubtitleLabel]; - [MarkIdentityAsSeenJob runWithThread:self.thread]; [ProfileFetcherJob runWithThread:self.thread networkManager:self.networkManager]; [self markVisibleMessagesAsRead]; @@ -1174,7 +1173,6 @@ typedef enum : NSUInteger { return [SafetyNumberConfirmationAlert presentAlertIfNecessaryWithRecipientIds:self.thread.recipientIdentifiers confirmationText:confirmationText contactsManager:self.contactsManager - verifySeen:NO completion:completionHandler]; } diff --git a/Signal/src/ViewControllers/DebugUI/DebugUITableViewController.m b/Signal/src/ViewControllers/DebugUI/DebugUITableViewController.m index 013f09cb6a..c782078c9e 100644 --- a/Signal/src/ViewControllers/DebugUI/DebugUITableViewController.m +++ b/Signal/src/ViewControllers/DebugUI/DebugUITableViewController.m @@ -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 - presentRejectedCallWithUnseenIdentityChange: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]; diff --git a/Signal/src/ViewControllers/FingerprintViewController.m b/Signal/src/ViewControllers/FingerprintViewController.m index 913c2406e6..372bf25f12 100644 --- a/Signal/src/ViewControllers/FingerprintViewController.m +++ b/Signal/src/ViewControllers/FingerprintViewController.m @@ -11,8 +11,8 @@ #import #import #import +#import #import -#import #import #import diff --git a/Signal/src/ViewControllers/NewGroupViewController.m b/Signal/src/ViewControllers/NewGroupViewController.m index 2deb7ff2f5..13481b8081 100644 --- a/Signal/src/ViewControllers/NewGroupViewController.m +++ b/Signal/src/ViewControllers/NewGroupViewController.m @@ -261,7 +261,6 @@ const NSUInteger kNewGroupViewControllerAvatarWidth = 68; @"their safety " @"number has recently changed") contactsManager:contactsViewHelper.contactsManager - verifySeen:YES completion:^(BOOL didConfirmIdentity) { if (didConfirmIdentity) { [weakSelf addRecipientId:recipientId]; @@ -351,7 +350,6 @@ const NSUInteger kNewGroupViewControllerAvatarWidth = 68; @"their safety " @"number has recently changed") contactsManager:contactsViewHelper.contactsManager - verifySeen:YES completion:^(BOOL didConfirmIdentity) { if (didConfirmIdentity) { [weakSelf addRecipientId:recipientId]; diff --git a/Signal/src/ViewControllers/OWSLinkDeviceViewController.m b/Signal/src/ViewControllers/OWSLinkDeviceViewController.m index 1203f9401c..73cd9812a5 100644 --- a/Signal/src/ViewControllers/OWSLinkDeviceViewController.m +++ b/Signal/src/ViewControllers/OWSLinkDeviceViewController.m @@ -8,7 +8,7 @@ #import "SettingsTableViewController.h" #import #import -#import +#import #import NS_ASSUME_NONNULL_BEGIN @@ -128,8 +128,10 @@ NS_ASSUME_NONNULL_BEGIN - (void)provisionWithParser:(OWSDeviceProvisioningURLParser *)parser { - NSData *myPublicKey = [[TSStorageManager sharedManager] identityKeyPair].publicKey; - NSData *myPrivateKey = [[TSStorageManager sharedManager] identityKeyPair].ows_privateKey; + ECKeyPair *_Nullable identityKeyPair = [[OWSIdentityManager sharedManager] identityKeyPair]; + OWSAssert(identityKeyPair); + NSData *myPublicKey = identityKeyPair.publicKey; + NSData *myPrivateKey = identityKeyPair.ows_privateKey; NSString *accountIdentifier = [TSStorageManager localNumber]; OWSDeviceProvisioner *provisioner = [[OWSDeviceProvisioner alloc] initWithMyPublicKey:myPublicKey diff --git a/Signal/src/ViewControllers/SafetyNumberConfirmationAlert.swift b/Signal/src/ViewControllers/SafetyNumberConfirmationAlert.swift index 6f5515d4f3..0836ec4aca 100644 --- a/Signal/src/ViewControllers/SafetyNumberConfirmationAlert.swift +++ b/Signal/src/ViewControllers/SafetyNumberConfirmationAlert.swift @@ -16,14 +16,13 @@ class SafetyNumberConfirmationAlert: NSObject { self.storageManager = TSStorageManager.shared() } - public class func presentAlertIfNecessary(recipientId: String, confirmationText: String, contactsManager: OWSContactsManager, verifySeen: Bool, completion: @escaping (Bool) -> Void) -> Bool { - return self.presentAlertIfNecessary(recipientIds: [recipientId], confirmationText: confirmationText, contactsManager: contactsManager, verifySeen: verifySeen, completion: completion) + public class func presentAlertIfNecessary(recipientId: String, confirmationText: String, contactsManager: OWSContactsManager, completion: @escaping (Bool) -> Void) -> Bool { + return self.presentAlertIfNecessary(recipientIds: [recipientId], confirmationText: confirmationText, contactsManager: contactsManager, completion: completion) } - public class func presentAlertIfNecessary(recipientIds: [String], confirmationText: String, contactsManager: OWSContactsManager, verifySeen: Bool, completion: @escaping (Bool) -> Void) -> Bool { + public class func presentAlertIfNecessary(recipientIds: [String], confirmationText: String, contactsManager: OWSContactsManager, completion: @escaping (Bool) -> Void) -> Bool { return SafetyNumberConfirmationAlert(contactsManager: contactsManager).presentIfNecessary(recipientIds: recipientIds, confirmationText: confirmationText, - verifySeen: verifySeen, completion: completion) } @@ -33,27 +32,14 @@ class SafetyNumberConfirmationAlert: NSObject { * @returns true if an alert was shown * false if there were no unconfirmed identities */ - public func presentIfNecessary(recipientIds: [String], confirmationText: String, verifySeen: Bool, completion: @escaping (Bool) -> Void) -> Bool { + public func presentIfNecessary(recipientIds: [String], confirmationText: String, completion: @escaping (Bool) -> Void) -> Bool { - let unconfirmedIdentity = unconfirmedIdentities(recipientIds: recipientIds).first - - var unseenIdentity: OWSRecipientIdentity? - if verifySeen { - unseenIdentity = unseenIdentities(recipientIds: recipientIds).first - } - - guard let untrustedIdentity = [unseenIdentity, unconfirmedIdentity].flatMap({ $0 }).first else { + guard let untrustedIdentity = untrustedIdentityForSending(recipientIds: recipientIds) else { // No identities to confirm, no alert to present. return false } - let displayName: String = { - if let signalAccount = contactsManager.signalAccountMap[untrustedIdentity.recipientId] { - return contactsManager.displayName(for: signalAccount) - } else { - return contactsManager.displayName(forPhoneIdentifier: untrustedIdentity.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}}") @@ -69,11 +55,7 @@ class SafetyNumberConfirmationAlert: NSObject { Logger.info("\(self.TAG) Confirmed identity: \(untrustedIdentity)") OWSDispatch.sessionStoreQueue().async { - self.storageManager.saveRemoteIdentity(untrustedIdentity.identityKey, - recipientId: untrustedIdentity.recipientId, - approvedForBlockingUse: true, - approvedForNonBlockingUse: true) - MarkIdentityAsSeenJob.run(recipientId: untrustedIdentity.recipientId) + OWSIdentityManager.shared().setVerificationState(.default, identityKey: untrustedIdentity.identityKey, recipientId: untrustedIdentity.recipientId, sendSyncMessage: true) DispatchQueue.main.async { completion(true) } @@ -110,16 +92,9 @@ class SafetyNumberConfirmationAlert: NSObject { UIApplication.shared.frontmostViewController?.present(fingerprintViewController, animated: true, completion: completion) } - private func unconfirmedIdentities(recipientIds: [String]) -> [OWSRecipientIdentity] { + private func untrustedIdentityForSending(recipientIds: [String]) -> OWSRecipientIdentity? { return recipientIds.flatMap { - self.storageManager.unconfirmedIdentityThatShouldBlockSending(forRecipientId: $0) - } + OWSIdentityManager.shared().untrustedIdentityForSending(toRecipientId: $0) + }.first } - - private func unseenIdentities(recipientIds: [String]) -> [OWSRecipientIdentity] { - return recipientIds.flatMap { - self.storageManager.unseenIdentityChange(forRecipientId: $0) - } - } - } diff --git a/Signal/src/call/CallService.swift b/Signal/src/call/CallService.swift index 07229e4ad8..9cb75a79c5 100644 --- a/Signal/src/call/CallService.swift +++ b/Signal/src/call/CallService.swift @@ -470,9 +470,22 @@ protocol CallServiceObserver: class { let newCall = SignalCall.incomingCall(localId: UUID(), remotePhoneNumber: thread.contactIdentifier(), signalingId: callId) - guard self.storageManager.unseenIdentityChange(forRecipientId: thread.contactIdentifier()) == nil else { + let untrustedIdentity = OWSIdentityManager.shared().untrustedIdentityForSending(toRecipientId: thread.contactIdentifier()) + + guard untrustedIdentity == nil else { let callerName = self.contactsManager.displayName(forPhoneIdentifier: thread.contactIdentifier()) - self.notificationsAdapter.presentRejectedCallWithUnseenIdentityChange(newCall, callerName: callerName) + + switch(untrustedIdentity!.verificationState) { + case .verified: + Logger.error("\(TAG) shouldn't have missed a call due to untrusted identity if the identity is 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 } diff --git a/Signal/src/call/OutboundCallInitiator.swift b/Signal/src/call/OutboundCallInitiator.swift index 144fbc1afe..e898e5c337 100644 --- a/Signal/src/call/OutboundCallInitiator.swift +++ b/Signal/src/call/OutboundCallInitiator.swift @@ -48,8 +48,7 @@ import Foundation let showedAlert = SafetyNumberConfirmationAlert.presentAlertIfNecessary(recipientId: recipientId, confirmationText: CallStrings.confirmAndCallButtonTitle, - contactsManager: self.contactsManager, - verifySeen: true) { didConfirmIdentity in + contactsManager: self.contactsManager) { didConfirmIdentity in if didConfirmIdentity { _ = self.initiateCall(recipientId: recipientId) } diff --git a/Signal/src/call/UserInterface/OWSCallNotificationsAdaptee.h b/Signal/src/call/UserInterface/OWSCallNotificationsAdaptee.h index d80a09319c..4e6c12c187 100644 --- a/Signal/src/call/UserInterface/OWSCallNotificationsAdaptee.h +++ b/Signal/src/call/UserInterface/OWSCallNotificationsAdaptee.h @@ -4,6 +4,7 @@ NS_ASSUME_NONNULL_BEGIN +@class OWSRecipientIdentity; @class SignalCall; @protocol OWSCallNotificationsAdaptee @@ -12,9 +13,13 @@ NS_ASSUME_NONNULL_BEGIN - (void)presentMissedCall:(SignalCall *)call callerName:(NSString *)callerName; -- (void)presentRejectedCallWithUnseenIdentityChange:(SignalCall *)call - callerName:(NSString *)callerName - NS_SWIFT_NAME(presentRejectedCallWithUnseenIdentityChange(_:callerName:)); +- (void)presentMissedCallBecauseOfNewIdentity:(SignalCall *)call + callerName:(NSString *)callerName + NS_SWIFT_NAME(presentMissedCallBecauseOfNewIdentity(call:callerName:)); + +- (void)presentMissedCallBecauseOfNoLongerVerifiedIdentity:(SignalCall *)call + callerName:(NSString *)callerName + NS_SWIFT_NAME(presentMissedCallBecauseOfNoLongerVerifiedIdentity(call:callerName:)); @end diff --git a/Signal/src/environment/Migrations/OWS104CreateRecipientIdentities.m b/Signal/src/environment/Migrations/OWS104CreateRecipientIdentities.m index 7077eaeeeb..fc2407acae 100644 --- a/Signal/src/environment/Migrations/OWS104CreateRecipientIdentities.m +++ b/Signal/src/environment/Migrations/OWS104CreateRecipientIdentities.m @@ -3,8 +3,8 @@ // #import "OWS104CreateRecipientIdentities.h" +#import #import -#import #import #import @@ -54,8 +54,8 @@ static NSString *const OWS104CreateRecipientIdentitiesMigrationId = @"104"; identityKey:identityKey isFirstKnownKey:NO createdAt:[NSDate dateWithTimeIntervalSince1970:0] - approvedForBlockingUse:YES - approvedForNonBlockingUse:NO] saveWithTransaction:transaction]; + verificationState:OWSVerificationStateDefault] + saveWithTransaction:transaction]; }]; [self saveWithTransaction:transaction]; diff --git a/Signal/src/environment/NotificationsManager.m b/Signal/src/environment/NotificationsManager.m index 2e72eadbcd..c3831eb795 100644 --- a/Signal/src/environment/NotificationsManager.m +++ b/Signal/src/environment/NotificationsManager.m @@ -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)presentRejectedCallWithUnseenIdentityChange:(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 = PushManagerCategoriesRejectedCallFromUnseenIdentityChange; + // Use category which allows call back + notification.category = PushManagerCategoriesMissedCall; NSString *localCallId = call.localId.UUIDString; notification.userInfo = @{ PushManagerUserInfoKeysLocalCallId : localCallId, @@ -130,17 +132,53 @@ NSString *alertMessage; switch (self.notificationPreviewType) { case NotificationNoNameNoPreview: { - alertMessage = [CallStrings rejectedCallWithUnseenIdentityChangeNotificationBody]; + alertMessage = [CallStrings missedCallWithIdentityChangeNotificationBodyWithoutCallerName]; break; } case NotificationNameNoPreview: case NotificationNamePreview: { alertMessage = (([UIDevice currentDevice].supportsCallKit && [[Environment getCurrent].preferences isCallKitPrivacyEnabled]) - ? [CallStrings rejectedCallWithUnseenIdentityChangeNotificationBodyWithoutCallerName] + ? [CallStrings missedCallWithIdentityChangeNotificationBodyWithoutCallerName] : [NSString - stringWithFormat:[CallStrings - rejectedCallWithUnseenIdentityChangeNotificationBodyWithCallerName], + 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; } diff --git a/Signal/src/network/PushManager.h b/Signal/src/network/PushManager.h index c3a93c33d6..c319a3980e 100644 --- a/Signal/src/network/PushManager.h +++ b/Signal/src/network/PushManager.h @@ -22,12 +22,11 @@ extern NSString *const Signal_Message_MarkAsRead_Identifier; extern NSString *const PushManagerCategoriesIncomingCall; extern NSString *const PushManagerCategoriesMissedCall; -extern NSString *const PushManagerCategoriesRejectedCallFromUnseenIdentityChange; +extern NSString *const PushManagerCategoriesMissedCallFromNoLongerVerifiedIdentity; extern NSString *const PushManagerActionsAcceptCall; extern NSString *const PushManagerActionsDeclineCall; extern NSString *const PushManagerActionsCallBack; -extern NSString *const PushManagerActionsConfirmIdentityAndCallBack; extern NSString *const PushManagerActionsShowThread; extern NSString *const PushManagerUserInfoKeysCallBackSignalRecipientId; diff --git a/Signal/src/network/PushManager.m b/Signal/src/network/PushManager.m index fe242de846..cdcbfb8180 100644 --- a/Signal/src/network/PushManager.m +++ b/Signal/src/network/PushManager.m @@ -207,18 +207,6 @@ NSString *const Signal_Message_MarkAsRead_Identifier = @"Signal_Message_MarkAsRe return; } - [self.callUIAdapter startAndShowOutgoingCallWithRecipientId:recipientId]; - completionHandler(); - } else if ([identifier isEqualToString:PushManagerActionsConfirmIdentityAndCallBack]) { - NSString *recipientId = notification.userInfo[PushManagerUserInfoKeysCallBackSignalRecipientId]; - if (!recipientId) { - DDLogError(@"%@ missing call back id", self.tag); - return; - } - - TSContactThread *thread = [TSContactThread getOrCreateThreadWithContactId:recipientId]; - [MarkIdentityAsSeenJob runWithThread:thread]; - [self.callUIAdapter startAndShowOutgoingCallWithRecipientId:recipientId]; completionHandler(); } else if ([identifier isEqualToString:PushManagerActionsShowThread]) { @@ -357,13 +345,14 @@ NSString *const Signal_Message_MarkAsRead_Identifier = @"Signal_Message_MarkAsRe NSString *const PushManagerCategoriesIncomingCall = @"PushManagerCategoriesIncomingCall"; NSString *const PushManagerCategoriesMissedCall = @"PushManagerCategoriesMissedCall"; -NSString *const PushManagerCategoriesRejectedCallFromUnseenIdentityChange = - @"PushManagerCategoriesRejectedCallFromUnseenIdentityChange"; +NSString *const PushManagerCategoriesMissedCallFromNoLongerVerifiedIdentity = + @"PushManagerCategoriesMissedCallFromNoLongerVerifiedIdentity"; NSString *const PushManagerActionsAcceptCall = @"PushManagerActionsAcceptCall"; NSString *const PushManagerActionsDeclineCall = @"PushManagerActionsDeclineCall"; NSString *const PushManagerActionsCallBack = @"PushManagerActionsCallBack"; -NSString *const PushManagerActionsConfirmIdentityAndCallBack = @"PushManagerActionsConfirmIdentityAndCallBack"; +NSString *const PushManagerActionsIgnoreIdentityChangeAndCallBack = + @"PushManagerActionsIgnoreIdentityChangeAndCallBack"; NSString *const PushManagerActionsShowThread = @"PushManagerActionsShowThread"; NSString *const PushManagerUserInfoKeysLocalCallId = @"PushManagerUserInfoKeysLocalCallId"; @@ -410,14 +399,8 @@ NSString *const PushManagerUserInfoKeysCallBackSignalRecipientId = @"PushManager return missedCallCategory; } -- (UIUserNotificationCategory *)signalRejectedCallWithUnseenIdentityChangeCategory +- (UIUserNotificationCategory *)signalMissedCallWithNoLongerVerifiedIdentityChangeCategory { - UIMutableUserNotificationAction *confirmAndCallBackAction = [UIMutableUserNotificationAction new]; - confirmAndCallBackAction.identifier = PushManagerActionsConfirmIdentityAndCallBack; - confirmAndCallBackAction.title = [CallStrings confirmIdentityAndCallBackButtonTitle]; - confirmAndCallBackAction.activationMode = UIUserNotificationActivationModeForeground; - confirmAndCallBackAction.destructive = NO; - confirmAndCallBackAction.authenticationRequired = YES; UIMutableUserNotificationAction *showThreadAction = [UIMutableUserNotificationAction new]; showThreadAction.identifier = PushManagerActionsShowThread; @@ -427,11 +410,9 @@ NSString *const PushManagerUserInfoKeysCallBackSignalRecipientId = @"PushManager showThreadAction.authenticationRequired = YES; UIMutableUserNotificationCategory *rejectedCallCategory = [UIMutableUserNotificationCategory new]; - rejectedCallCategory.identifier = PushManagerCategoriesRejectedCallFromUnseenIdentityChange; - [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; } @@ -452,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]; } diff --git a/Signal/translations/en.lproj/Localizable.strings b/Signal/translations/en.lproj/Localizable.strings index 9092bcaf13..08c90eec1c 100644 --- a/Signal/translations/en.lproj/Localizable.strings +++ b/Signal/translations/en.lproj/Localizable.strings @@ -241,9 +241,6 @@ /* No comment provided by engineer. */ "CONFIRM_ACCOUNT_DESTRUCTION_TITLE" = "Are you sure you want to delete your account?"; -/* notification action, confirming that it's OK to proceed calling after a caller's Safety Number has changed */ -"CONFIRM_IDENTITY_AND_CALLBACK_BUTTON_TITLE" = "Confirm and Call Back"; - /* Alert body */ "CONFIRM_LEAVE_GROUP_DESCRIPTION" = "You will no longer be able to send or receive messages in this group."; @@ -745,14 +742,11 @@ /* notification title */ "MISSED_CALL" = "Missed call"; -/* notification action */ -"MISSED_CALL_WITH_UNSEEN_IDENTITY_BODY" = "Missed call because the caller's safety number changed."; +/* notification title. Embeds {{caller's name or phone number}} */ +"MISSED_CALL_WITH_CHANGED_IDENTITY_BODY_WITH_CALLER_NAME" = "Missed call from %@ because their safety number changed."; -/* notification action */ -"MISSED_CALL_WITH_UNSEEN_IDENTITY_BODY_WITH_CALLER_NAME" = "Missed call from %@ because their safety number changed."; - -/* notification action */ -"MISSED_CALL_WITH_UNSEEN_IDENTITY_BODY_WITHOUT_CALLER_NAME" = "Missed call because the caller's safety number changed."; +/* notification title */ +"MISSED_CALL_WITH_CHANGED_IDENTITY_BODY_WITHOUT_CALLER_NAME" = "Missed call because the caller's safety number changed."; /* Alert body Alert body when camera is not authorized */ @@ -762,12 +756,9 @@ Alert title when camera is not authorized */ "MISSING_CAMERA_PERMISSION_TITLE" = "Signal needs to access your camera."; -/* notification title. Embeds {{Caller's Name}} */ +/* notification title. Embeds {{caller's name or phone number}} */ "MSGVIEW_MISSED_CALL_WITH_NAME" = "Missed call from %@."; -/* notification title. */ -"MSGVIEW_MISSED_CALL_WITHOUT_NAME" = "Missed call from Signal User."; - /* No comment provided by engineer. */ "MSGVIEW_RECEIVED_CALL" = "You received a call from %@."; @@ -1073,13 +1064,13 @@ "RETRY_BUTTON_TEXT" = "Retry"; /* button title to confirm adding a recipient to a group when their safety number has recently changed */ -"SAFETY_NUMBER_CHANGED_CONFIRM_ADD_TO_GROUP_ACTION" = "Confirm and Add to Group"; +"SAFETY_NUMBER_CHANGED_CONFIRM_ADD_TO_GROUP_ACTION" = "Add to Group Anyway"; /* alert button text to confirm placing an outgoing call after the recipients Safety Number has changed. */ -"SAFETY_NUMBER_CHANGED_CONFIRM_CALL_ACTION" = "Confirm and Call"; +"SAFETY_NUMBER_CHANGED_CONFIRM_CALL_ACTION" = "Call Anyway"; /* button title to confirm sending to a recipient whose safety number recently changed */ -"SAFETY_NUMBER_CHANGED_CONFIRM_SEND_ACTION" = "Confirm and Send"; +"SAFETY_NUMBER_CHANGED_CONFIRM_SEND_ACTION" = "Send Anyway"; /* Snippet to share {{safety number}} with a friend. sent e.g. via SMS */ "SAFETY_NUMBER_SHARE_FORMAT" = "Our Signal Safety Number:\n%@";