From 5cffe49cd24dda26fbf1261e2915754a9decfe13 Mon Sep 17 00:00:00 2001 From: Jordan Rose Date: Thu, 1 Sep 2022 13:10:41 -0700 Subject: [PATCH] CallKitIdStore: traffic in threads rather than addresses This will be the interface used for storing IDs of group calls in the future; for now there should be no functionality change, except if there's an address mentioned with no associated thread. Previously that thread would be created if needed; now the call action will fail. This seems reasonable given that threads only go away if the user explicitly deletes them. While here, we don't need to save both the UUID and phone number of a user's address; the UUID always wins anyway. Only worry about phone numbers if there's no UUID. --- Signal/src/AppDelegate.m | 30 +++++------- .../OutboundIndividualCallInitiator.swift | 6 ++- .../CallKit/CallKitCallManager.swift | 2 +- .../CallKit/CallKitCallUIAdaptee.swift | 2 +- .../src/Storage/AxolotlStore/CallKitIdStore.h | 20 ++------ .../src/Storage/AxolotlStore/CallKitIdStore.m | 46 +++++++++++-------- 6 files changed, 48 insertions(+), 58 deletions(-) diff --git a/Signal/src/AppDelegate.m b/Signal/src/AppDelegate.m index b2dc9f0422..a9672ca2ff 100644 --- a/Signal/src/AppDelegate.m +++ b/Signal/src/AppDelegate.m @@ -887,8 +887,8 @@ static void uncaughtExceptionHandler(NSException *exception) return; } - SignalServiceAddress *_Nullable address = [self addressForIntentHandle:handle]; - if (!address.isValid) { + TSThread *_Nullable thread = [self threadForIntentHandle:handle]; + if (!thread) { OWSLogWarn(@"ignoring attempt to initiate video call to unknown user."); return; } @@ -903,8 +903,7 @@ static void uncaughtExceptionHandler(NSException *exception) // to that user - unless there already is another call in progress. SignalCall *_Nullable currentCall = AppEnvironment.shared.callService.currentCall; if (currentCall != nil) { - if (currentCall.isIndividualCall && - [address isEqualToAddress:currentCall.individualCall.remoteAddress]) { + if (currentCall.isIndividualCall && [thread.uniqueId isEqual:currentCall.thread.uniqueId]) { OWSLogWarn(@"trying to upgrade ongoing call to video."); [AppEnvironment.shared.callService.individualCallService handleCallKitStartVideo]; return; @@ -914,7 +913,6 @@ static void uncaughtExceptionHandler(NSException *exception) } } - TSContactThread *thread = [TSContactThread getOrCreateThreadWithContactAddress:address]; OutboundIndividualCallInitiator *outboundIndividualCallInitiator = AppEnvironment.shared.outboundIndividualCallInitiator; OWSAssertDebug(outboundIndividualCallInitiator); @@ -944,8 +942,8 @@ static void uncaughtExceptionHandler(NSException *exception) return; } - SignalServiceAddress *_Nullable address = [self addressForIntentHandle:handle]; - if (!address.isValid) { + TSThread *_Nullable thread = [self threadForIntentHandle:handle]; + if (!thread) { OWSLogWarn(@"ignoring attempt to initiate audio call to unknown user."); return; } @@ -955,7 +953,6 @@ static void uncaughtExceptionHandler(NSException *exception) return; } - TSContactThread *thread = [TSContactThread getOrCreateThreadWithContactAddress:address]; OutboundIndividualCallInitiator *outboundIndividualCallInitiator = AppEnvironment.shared.outboundIndividualCallInitiator; OWSAssertDebug(outboundIndividualCallInitiator); @@ -991,8 +988,8 @@ static void uncaughtExceptionHandler(NSException *exception) return; } - SignalServiceAddress *_Nullable address = [self addressForIntentHandle:handle]; - if (!address.isValid) { + TSThread *_Nullable thread = [self threadForIntentHandle:handle]; + if (!thread) { OWSLogWarn(@"ignoring attempt to initiate call to unknown user."); return; } @@ -1002,7 +999,6 @@ static void uncaughtExceptionHandler(NSException *exception) return; } - TSContactThread *thread = [TSContactThread getOrCreateThreadWithContactAddress:address]; OutboundIndividualCallInitiator *outboundIndividualCallInitiator = AppEnvironment.shared.outboundIndividualCallInitiator; OWSAssertDebug(outboundIndividualCallInitiator); @@ -1026,23 +1022,19 @@ static void uncaughtExceptionHandler(NSException *exception) return NO; } -- (nullable SignalServiceAddress *)addressForIntentHandle:(NSString *)handle +- (nullable TSThread *)threadForIntentHandle:(NSString *)handle { OWSAssertDebug(handle.length > 0); if ([handle hasPrefix:CallKitCallManager.kAnonymousCallHandlePrefix]) { - SignalServiceAddress *_Nullable address = [CallKitIdStore addressForCallKitId:handle]; - if (!address.isValid) { - OWSLogWarn(@"ignoring attempt to initiate audio call to unknown anonymous signal user."); - return nil; - } - return address; + return [CallKitIdStore threadForCallKitId:handle]; } for (PhoneNumber *phoneNumber in [PhoneNumber tryParsePhoneNumbersFromUserSpecifiedText:handle clientPhoneNumber:[TSAccountManager localNumber]]) { - return [[SignalServiceAddress alloc] initWithPhoneNumber:phoneNumber.toE164]; + SignalServiceAddress *address = [[SignalServiceAddress alloc] initWithPhoneNumber:phoneNumber.toE164]; + return [TSContactThread getOrCreateThreadWithContactAddress:address]; } return nil; } diff --git a/Signal/src/Calls/Individual/OutboundIndividualCallInitiator.swift b/Signal/src/Calls/Individual/OutboundIndividualCallInitiator.swift index e5e35a813c..ad87f06dcf 100644 --- a/Signal/src/Calls/Individual/OutboundIndividualCallInitiator.swift +++ b/Signal/src/Calls/Individual/OutboundIndividualCallInitiator.swift @@ -24,7 +24,7 @@ public class OutboundIndividualCallInitiator: NSObject { */ @discardableResult @objc - public func initiateCall(thread: TSContactThread, isVideo: Bool) -> Bool { + public func initiateCall(thread: TSThread, isVideo: Bool) -> Bool { guard tsAccountManager.isOnboarded() else { Logger.warn("aborting due to user not being onboarded.") OWSActionSheets.showActionSheet(title: NSLocalizedString("YOU_MUST_COMPLETE_ONBOARDING_BEFORE_PROCEEDING", @@ -40,6 +40,10 @@ public class OutboundIndividualCallInitiator: NSObject { owsFailDebug("could not identify frontmostViewController") return false } + guard let thread = thread as? TSContactThread else { + owsFailDebug("cannot initiate call to group thread") + return false + } let showedAlert = SafetyNumberConfirmationSheet.presentIfNecessary( address: thread.contactAddress, diff --git a/Signal/src/Calls/UserInterface/CallKit/CallKitCallManager.swift b/Signal/src/Calls/UserInterface/CallKit/CallKitCallManager.swift index c49260df16..a9dd7fec3a 100644 --- a/Signal/src/Calls/UserInterface/CallKit/CallKitCallManager.swift +++ b/Signal/src/Calls/UserInterface/CallKit/CallKitCallManager.swift @@ -50,7 +50,7 @@ final class CallKitCallManager: NSObject { } else { let callKitId = CallKitCallManager.kAnonymousCallHandlePrefix + call.localId.uuidString handle = CXHandle(type: .generic, value: callKitId) - CallKitIdStore.setAddress(call.individualCall.remoteAddress, forCallKitId: callKitId) + CallKitIdStore.setThread(call.thread, forCallKitId: callKitId) } let startCallAction = CXStartCallAction(call: call.localId, handle: handle) diff --git a/Signal/src/Calls/UserInterface/CallKit/CallKitCallUIAdaptee.swift b/Signal/src/Calls/UserInterface/CallKit/CallKitCallUIAdaptee.swift index 6cba98f9c5..5964f300bf 100644 --- a/Signal/src/Calls/UserInterface/CallKit/CallKitCallUIAdaptee.swift +++ b/Signal/src/Calls/UserInterface/CallKit/CallKitCallUIAdaptee.swift @@ -154,7 +154,7 @@ final class CallKitCallUIAdaptee: NSObject, CallUIAdaptee, CXProviderDelegate { } else { let callKitId = CallKitCallManager.kAnonymousCallHandlePrefix + call.localId.uuidString update.remoteHandle = CXHandle(type: .generic, value: callKitId) - CallKitIdStore.setAddress(call.individualCall.remoteAddress, forCallKitId: callKitId) + CallKitIdStore.setThread(call.thread, forCallKitId: callKitId) update.localizedCallerName = NSLocalizedString("CALLKIT_ANONYMOUS_CONTACT_NAME", comment: "The generic name used for calls if CallKit privacy is enabled") } diff --git a/SignalServiceKit/src/Storage/AxolotlStore/CallKitIdStore.h b/SignalServiceKit/src/Storage/AxolotlStore/CallKitIdStore.h index f5477afebc..194887fede 100644 --- a/SignalServiceKit/src/Storage/AxolotlStore/CallKitIdStore.h +++ b/SignalServiceKit/src/Storage/AxolotlStore/CallKitIdStore.h @@ -1,27 +1,15 @@ // -// Copyright (c) 2019 Open Whisper Systems. All rights reserved. +// Copyright (c) 2022 Open Whisper Systems. All rights reserved. // NS_ASSUME_NONNULL_BEGIN -@class SDSKeyValueStore; -@class SignalServiceAddress; +@class TSThread; @interface CallKitIdStore : NSObject -+ (SDSKeyValueStore *)phoneNumberStore; -+ (SDSKeyValueStore *)uuidStore; - -// phoneNumber is an e164 formatted phone number. -// -// callKitId is expected to have CallKitCallManager.kAnonymousCallHandlePrefix. -+ (void)setAddress:(SignalServiceAddress *)address forCallKitId:(NSString *)callKitId; - -// returns an e164 formatted phone number or nil if no -// record can be found. -// -// callKitId is expected to have CallKitCallManager.kAnonymousCallHandlePrefix. -+ (SignalServiceAddress *)addressForCallKitId:(NSString *)callKitId; ++ (void)setThread:(TSThread *)thread forCallKitId:(NSString *)callKitId; ++ (nullable TSThread *)threadForCallKitId:(NSString *)callKitId; @end diff --git a/SignalServiceKit/src/Storage/AxolotlStore/CallKitIdStore.m b/SignalServiceKit/src/Storage/AxolotlStore/CallKitIdStore.m index e751950323..7600111b31 100644 --- a/SignalServiceKit/src/Storage/AxolotlStore/CallKitIdStore.m +++ b/SignalServiceKit/src/Storage/AxolotlStore/CallKitIdStore.m @@ -1,5 +1,5 @@ // -// Copyright (c) 2021 Open Whisper Systems. All rights reserved. +// Copyright (c) 2022 Open Whisper Systems. All rights reserved. // #import "CallKitIdStore.h" @@ -21,42 +21,48 @@ NS_ASSUME_NONNULL_BEGIN #pragma mark - -+ (void)setAddress:(SignalServiceAddress *)address forCallKitId:(NSString *)callKitId ++ (void)setThread:(TSThread *)thread forCallKitId:(NSString *)callKitId { - OWSAssertDebug(address.isValid); OWSAssertDebug(callKitId.length > 0); + OWSAssertDebug([thread isKindOfClass:[TSContactThread class]]); DatabaseStorageWrite(self.databaseStorage, ^(SDSAnyWriteTransaction *transaction) { - if (address.phoneNumber) { - [self.phoneNumberStore setString:address.phoneNumber key:callKitId transaction:transaction]; - } else { + SignalServiceAddress *address = [(TSContactThread *)thread contactAddress]; + NSString *uuidString = address.uuidString; + if (uuidString) { + [self.uuidStore setString:uuidString key:callKitId transaction:transaction]; [self.phoneNumberStore removeValueForKey:callKitId transaction:transaction]; - } - - if (address.uuidString) { - [self.uuidStore setString:address.uuidString key:callKitId transaction:transaction]; } else { + OWSFailDebug(@"making a call to an address with no UUID: %@", address.phoneNumber); + [self.phoneNumberStore setString:address.phoneNumber key:callKitId transaction:transaction]; [self.uuidStore removeValueForKey:callKitId transaction:transaction]; } }); } -+ (SignalServiceAddress *)addressForCallKitId:(NSString *)callKitId ++ (nullable TSThread *)threadForCallKitId:(NSString *)callKitId { OWSAssertDebug(callKitId.length > 0); - __block NSString *_Nullable phoneNumber; - __block NSString *_Nullable uuidString; + __block TSThread *_Nullable result; [self.databaseStorage readWithBlock:^(SDSAnyReadTransaction *transaction) { - phoneNumber = [self.phoneNumberStore getString:callKitId transaction:transaction]; - uuidString = [self.uuidStore getString:callKitId transaction:transaction]; + // Check for an ACI first, then phone numbers. + NSString *_Nullable uuidString = [self.uuidStore getString:callKitId transaction:transaction]; + if (uuidString) { + SignalServiceAddress *address = [[SignalServiceAddress alloc] initWithUuidString:uuidString]; + result = [TSContactThread getThreadWithContactAddress:address transaction:transaction]; + return; + } + + NSString *_Nullable phoneNumber = [self.phoneNumberStore getString:callKitId transaction:transaction]; + if (phoneNumber) { + SignalServiceAddress *address = [[SignalServiceAddress alloc] initWithPhoneNumber:phoneNumber]; + result = [TSContactThread getThreadWithContactAddress:address transaction:transaction]; + return; + } }]; - if (!phoneNumber && !uuidString) { - return nil; - } - - return [[SignalServiceAddress alloc] initWithUuidString:uuidString phoneNumber:phoneNumber]; + return result; } @end