Remove unused CDSv1 code

It’s been replaced by CDSv2.
This commit is contained in:
Max Radermacher 2023-02-22 14:43:09 -08:00 committed by GitHub
parent fdbdc9716d
commit 6dede44db6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 32 additions and 540 deletions

View File

@ -775,7 +775,7 @@
506A924F28FA232100A2EFC2 /* ContactDiscoveryManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 506A924E28FA232100A2EFC2 /* ContactDiscoveryManager.swift */; };
506A92512900888900A2EFC2 /* RecipientPickerContainerViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 506A92502900888900A2EFC2 /* RecipientPickerContainerViewController.swift */; };
506A9252290326A600A2EFC2 /* TextHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4521C3BF1F59F3BA00B4C582 /* TextHelper.swift */; };
5075004628B09CE6001922C9 /* ContactDiscoveryOperationTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C4BC6C22102D697004040C9 /* ContactDiscoveryOperationTest.swift */; };
5075004628B09CE6001922C9 /* ContactDiscoveryE164CollectionTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C4BC6C22102D697004040C9 /* ContactDiscoveryE164CollectionTest.swift */; };
507CD5E529660D5100E47DAC /* ServiceId.swift in Sources */ = {isa = PBXBuildFile; fileRef = 507CD5E429660D5100E47DAC /* ServiceId.swift */; };
508F0346296F72F4001D88D0 /* CustomCellBackgroundColor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 508F0345296F72F4001D88D0 /* CustomCellBackgroundColor.swift */; };
509913BE2913274100F34F8E /* PhoneNumberFinderTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 509913BD2913274100F34F8E /* PhoneNumberFinderTests.swift */; };
@ -1738,7 +1738,6 @@
F9C5CCBB289453B300548EEE /* PhoneNumberUtil.m in Sources */ = {isa = PBXBuildFile; fileRef = F9C5C9D3289453B100548EEE /* PhoneNumberUtil.m */; settings = {COMPILER_FLAGS = "-fcxx-modules"; }; };
F9C5CCBC289453B300548EEE /* PhoneNumber.m in Sources */ = {isa = PBXBuildFile; fileRef = F9C5C9D4289453B100548EEE /* PhoneNumber.m */; settings = {COMPILER_FLAGS = "-fcxx-modules"; }; };
F9C5CCBD289453B300548EEE /* UUIDBackfillTask.swift in Sources */ = {isa = PBXBuildFile; fileRef = F9C5C9D6289453B100548EEE /* UUIDBackfillTask.swift */; settings = {COMPILER_FLAGS = "-fcxx-modules"; }; };
F9C5CCBE289453B300548EEE /* SGXContactDiscoveryOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = F9C5C9D7289453B100548EEE /* SGXContactDiscoveryOperation.swift */; settings = {COMPILER_FLAGS = "-fcxx-modules"; }; };
F9C5CCC0289453B300548EEE /* ContactDiscoveryTask.swift in Sources */ = {isa = PBXBuildFile; fileRef = F9C5C9D9289453B100548EEE /* ContactDiscoveryTask.swift */; settings = {COMPILER_FLAGS = "-fcxx-modules"; }; };
F9C5CCC3289453B300548EEE /* ContactDiscoveryOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = F9C5C9DC289453B100548EEE /* ContactDiscoveryOperation.swift */; settings = {COMPILER_FLAGS = "-fcxx-modules"; }; };
F9C5CCC4289453B300548EEE /* OWSDisappearingMessagesConfiguration+SDS.swift in Sources */ = {isa = PBXBuildFile; fileRef = F9C5C9DD289453B100548EEE /* OWSDisappearingMessagesConfiguration+SDS.swift */; settings = {COMPILER_FLAGS = "-fcxx-modules"; }; };
@ -1989,7 +1988,6 @@
F9C5CDBE289453B400548EEE /* RESTNetworkManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = F9C5CAEB289453B200548EEE /* RESTNetworkManager.swift */; settings = {COMPILER_FLAGS = "-fcxx-modules"; }; };
F9C5CDBF289453B400548EEE /* OWSUploadOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = F9C5CAEC289453B200548EEE /* OWSUploadOperation.m */; settings = {COMPILER_FLAGS = "-fcxx-modules"; }; };
F9C5CDC0289453B400548EEE /* RESTNetworkManager.m in Sources */ = {isa = PBXBuildFile; fileRef = F9C5CAED289453B200548EEE /* RESTNetworkManager.m */; settings = {COMPILER_FLAGS = "-fcxx-modules"; }; };
F9C5CDC1289453B400548EEE /* ContactDiscoveryService.swift in Sources */ = {isa = PBXBuildFile; fileRef = F9C5CAEE289453B200548EEE /* ContactDiscoveryService.swift */; settings = {COMPILER_FLAGS = "-fcxx-modules"; }; };
F9C5CDC2289453B400548EEE /* HTTPEntities.swift in Sources */ = {isa = PBXBuildFile; fileRef = F9C5CAEF289453B200548EEE /* HTTPEntities.swift */; settings = {COMPILER_FLAGS = "-fcxx-modules"; }; };
F9C5CDC3289453B400548EEE /* DeviceProvisioningService.swift in Sources */ = {isa = PBXBuildFile; fileRef = F9C5CAF0289453B200548EEE /* DeviceProvisioningService.swift */; settings = {COMPILER_FLAGS = "-fcxx-modules"; }; };
F9C5CDC4289453B400548EEE /* NetworkInterfaceSet.swift in Sources */ = {isa = PBXBuildFile; fileRef = F9C5CAF1289453B200548EEE /* NetworkInterfaceSet.swift */; settings = {COMPILER_FLAGS = "-fcxx-modules"; }; };
@ -3118,7 +3116,7 @@
4C42960F231A1AA400D9D240 /* MessageSendingPerformanceTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MessageSendingPerformanceTest.swift; sourceTree = "<group>"; };
4C46361022EB98EC00185951 /* CameraFirstCaptureSendFlow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CameraFirstCaptureSendFlow.swift; sourceTree = "<group>"; };
4C4AE69F224AF21900D4AF6F /* SendMediaNavigationController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SendMediaNavigationController.swift; sourceTree = "<group>"; };
4C4BC6C22102D697004040C9 /* ContactDiscoveryOperationTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContactDiscoveryOperationTest.swift; sourceTree = "<group>"; };
4C4BC6C22102D697004040C9 /* ContactDiscoveryE164CollectionTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContactDiscoveryE164CollectionTest.swift; sourceTree = "<group>"; };
4C5250D121E7BD7D00CE3D95 /* PhoneNumberValidator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PhoneNumberValidator.swift; sourceTree = "<group>"; };
4C5250D321E7C51900CE3D95 /* PhoneNumberValidatorTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PhoneNumberValidatorTest.swift; sourceTree = "<group>"; };
4C63CBFF210A620B003AE45C /* SignalTSan.supp */ = {isa = PBXFileReference; lastKnownFileType = text; path = SignalTSan.supp; sourceTree = "<group>"; };
@ -4256,7 +4254,6 @@
F9C5C9D3289453B100548EEE /* PhoneNumberUtil.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PhoneNumberUtil.m; sourceTree = "<group>"; };
F9C5C9D4289453B100548EEE /* PhoneNumber.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PhoneNumber.m; sourceTree = "<group>"; };
F9C5C9D6289453B100548EEE /* UUIDBackfillTask.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UUIDBackfillTask.swift; sourceTree = "<group>"; };
F9C5C9D7289453B100548EEE /* SGXContactDiscoveryOperation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SGXContactDiscoveryOperation.swift; sourceTree = "<group>"; };
F9C5C9D9289453B100548EEE /* ContactDiscoveryTask.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ContactDiscoveryTask.swift; sourceTree = "<group>"; };
F9C5C9DC289453B100548EEE /* ContactDiscoveryOperation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ContactDiscoveryOperation.swift; sourceTree = "<group>"; };
F9C5C9DD289453B100548EEE /* OWSDisappearingMessagesConfiguration+SDS.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "OWSDisappearingMessagesConfiguration+SDS.swift"; sourceTree = "<group>"; };
@ -4507,7 +4504,6 @@
F9C5CAEB289453B200548EEE /* RESTNetworkManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RESTNetworkManager.swift; sourceTree = "<group>"; };
F9C5CAEC289453B200548EEE /* OWSUploadOperation.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWSUploadOperation.m; sourceTree = "<group>"; };
F9C5CAED289453B200548EEE /* RESTNetworkManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RESTNetworkManager.m; sourceTree = "<group>"; };
F9C5CAEE289453B200548EEE /* ContactDiscoveryService.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ContactDiscoveryService.swift; sourceTree = "<group>"; };
F9C5CAEF289453B200548EEE /* HTTPEntities.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HTTPEntities.swift; sourceTree = "<group>"; };
F9C5CAF0289453B200548EEE /* DeviceProvisioningService.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DeviceProvisioningService.swift; sourceTree = "<group>"; };
F9C5CAF1289453B200548EEE /* NetworkInterfaceSet.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NetworkInterfaceSet.swift; sourceTree = "<group>"; };
@ -6291,8 +6287,8 @@
5075004528B09CCC001922C9 /* Discovery */ = {
isa = PBXGroup;
children = (
4C4BC6C22102D697004040C9 /* ContactDiscoveryE164CollectionTest.swift */,
50169694291B0627007AD709 /* ContactDiscoveryManagerTest.swift */,
4C4BC6C22102D697004040C9 /* ContactDiscoveryOperationTest.swift */,
500824CF292741D5005A5DC0 /* ContactDiscoveryV2OperationTest.swift */,
);
path = Discovery;
@ -8444,7 +8440,6 @@
F9C5C9D9289453B100548EEE /* ContactDiscoveryTask.swift */,
5049FA2E28BEAABE00D6E099 /* ContactDiscoveryV2Connection.swift */,
5049FA2D28BEAABE00D6E099 /* ContactDiscoveryV2Operation.swift */,
F9C5C9D7289453B100548EEE /* SGXContactDiscoveryOperation.swift */,
F9C5C9D6289453B100548EEE /* UUIDBackfillTask.swift */,
);
path = Discovery;
@ -8813,7 +8808,6 @@
children = (
F9C5CADB289453B200548EEE /* Giphy */,
F9C5CAE1289453B200548EEE /* Requests */,
F9C5CAEE289453B200548EEE /* ContactDiscoveryService.swift */,
505C2ED529971D4E00C23FB2 /* DeviceLimitExceededError.swift */,
F9C5CAF0289453B200548EEE /* DeviceProvisioningService.swift */,
F9C5CAEF289453B200548EEE /* HTTPEntities.swift */,
@ -11465,7 +11459,6 @@
F9C5CCE4289453B300548EEE /* Contact.swift in Sources */,
506A924F28FA232100A2EFC2 /* ContactDiscoveryManager.swift in Sources */,
F9C5CCC3289453B300548EEE /* ContactDiscoveryOperation.swift in Sources */,
F9C5CDC1289453B400548EEE /* ContactDiscoveryService.swift in Sources */,
F9C5CCC0289453B300548EEE /* ContactDiscoveryTask.swift in Sources */,
5049FA3028BEAABE00D6E099 /* ContactDiscoveryV2Connection.swift in Sources */,
5049FA2F28BEAABE00D6E099 /* ContactDiscoveryV2Operation.swift in Sources */,
@ -11872,7 +11865,6 @@
F9C5CC96289453B300548EEE /* SessionRecord.pb.swift in Sources */,
F9C5CD35289453B300548EEE /* SessionRecordMigration.swift in Sources */,
1700E34128BD41150073D949 /* SetAlgebra+SSK.swift in Sources */,
F9C5CCBE289453B300548EEE /* SGXContactDiscoveryOperation.swift in Sources */,
F9C5CCC6289453B300548EEE /* SignalAccount+SDS.swift in Sources */,
F9C5CCD9289453B300548EEE /* SignalAccount.m in Sources */,
F9C5CCC5289453B300548EEE /* SignalAccount.swift in Sources */,
@ -12069,8 +12061,8 @@
F9426273289B1B5500460798 /* BlockingManagerStateTests.swift in Sources */,
F9426283289B1B5600460798 /* BlockingManagerTests.swift in Sources */,
661396AF28BE881E00E0C4DF /* ChainedPromiseTest.swift in Sources */,
5075004628B09CE6001922C9 /* ContactDiscoveryE164CollectionTest.swift in Sources */,
50169695291B0627007AD709 /* ContactDiscoveryManagerTest.swift in Sources */,
5075004628B09CE6001922C9 /* ContactDiscoveryOperationTest.swift in Sources */,
500824D0292741D5005A5DC0 /* ContactDiscoveryV2OperationTest.swift in Sources */,
F962B38C293F9F9F00765BD8 /* CRC32Test.swift in Sources */,
509BBF7A28CA556700F4D8A0 /* Data+SSKTest.swift in Sources */,

View File

@ -78,15 +78,8 @@ public class ContactDiscoveryError: NSError, UserErrorDescriptionProvider {
case generic = 1
case assertion
/// An error indicating that the current user has an expired auth token
case unauthorized
/// An error indicating that a hardcoded resource is unavailable. Best recourse is to update the app.
case unexpectedResponse
/// An error indicating response timeout.
case timeout
/// An error indicating that the failure was because of a rate limit
case rateLimit
/// Any generic 4xx error that doesn't fit in the above categories
case genericClientError
/// Any generic 5xx error that doesn't fit in the above categories

View File

@ -42,11 +42,7 @@ final class ContactDiscoveryTaskQueueImpl: ContactDiscoveryTaskQueue, Dependenci
}
private static func createContactDiscoveryOperation(for e164s: Set<E164>, mode: ContactDiscoveryMode) -> ContactDiscoveryOperation {
if !RemoteConfig.contactDiscoveryV2KillSwitch {
return ContactDiscoveryV2CompatibilityOperation(e164sToLookup: e164s, mode: mode)
} else {
return SGXContactDiscoveryOperation(e164sToLookup: e164s, mode: mode)
}
return ContactDiscoveryV2CompatibilityOperation(e164sToLookup: e164s, mode: mode)
}
private static func storeResults(

View File

@ -1,232 +0,0 @@
//
// Copyright 2018 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only
//
import Foundation
import LibSignalClient
struct CDSRegisteredContact: Hashable {
let signalUuid: UUID
let e164PhoneNumber: E164
}
/// Fetches contact info from the ContactDiscoveryService
/// Intended to be used by ContactDiscoveryTaskQueue. You probably don't want to use this directly.
class SGXContactDiscoveryOperation: ContactDiscoveryOperation {
static let batchSize = 2048
private let e164sToLookup: Set<E164>
required init(e164sToLookup: Set<E164>, mode: ContactDiscoveryMode) {
self.e164sToLookup = e164sToLookup
Logger.debug("with e164sToLookup.count: \(e164sToLookup.count)")
}
func perform(on queue: DispatchQueue) -> Promise<Set<DiscoveredContactInfo>> {
firstly { () -> Promise<[Set<CDSRegisteredContact>]> in
// First, build a bunch of batch Promises
let batchOperationPromises = Array(e164sToLookup)
.chunked(by: Self.batchSize)
.map { makeContactDiscoveryRequest(e164sToLookup: Array($0)) }
// Then, wait for them all to be fulfilled before joining the subsets together
return Promise.when(fulfilled: batchOperationPromises)
}.map(on: queue) { (setArray) -> Set<DiscoveredContactInfo> in
setArray.reduce(into: Set()) { (builder, cdsContactSubset) in
builder.formUnion(cdsContactSubset.map {
DiscoveredContactInfo(e164: $0.e164PhoneNumber, uuid: $0.signalUuid)
})
}
}.recover(on: queue) { error -> Promise<Set<DiscoveredContactInfo>> in
throw Self.prepareExternalError(from: error)
}
}
// Below, we have a bunch of then blocks being performed on a global concurrent queue
// It might be worthwhile to audit and see if we can move these onto the queue passed into `perform(on:)`
private func makeContactDiscoveryRequest(e164sToLookup: [E164]) -> Promise<Set<CDSRegisteredContact>> {
firstly { () -> Promise<RemoteAttestation.CDSAttestation> in
RemoteAttestation.performForCDS()
}.then(on: DispatchQueue.global()) { (attestation: RemoteAttestation.CDSAttestation) -> Promise<(RemoteAttestation.CDSAttestation, ContactDiscoveryService.IntersectionResponse)> in
let service = ContactDiscoveryService()
let query = try self.buildIntersectionQuery(e164sToLookup: e164sToLookup,
remoteAttestations: attestation.remoteAttestations)
return service.getRegisteredSignalUsers(
query: query,
cookies: attestation.cookies,
authUsername: attestation.auth.username,
authPassword: attestation.auth.password,
enclaveName: attestation.enclaveConfig.enclaveName,
host: attestation.enclaveConfig.host,
censorshipCircumventionPrefix: attestation.enclaveConfig.censorshipCircumventionPrefix
).map {(attestation, $0)}
}.map(on: DispatchQueue.global()) { attestation, response -> Set<CDSRegisteredContact> in
let allEnclaveAttestations = attestation.remoteAttestations
let respondingEnclaveAttestation = allEnclaveAttestations.first(where: { $1.requestId == response.requestId })
guard let responseAttestion = respondingEnclaveAttestation?.value else {
throw ContactDiscoveryError.assertionError(description: "Invalid responding enclave for requestId: \(response.requestId)")
}
let plaintext = try Aes256GcmEncryptedData(
nonce: response.iv,
ciphertext: response.data,
authenticationTag: response.mac
).decrypt(key: responseAttestion.keys.serverKey.keyData)
// 16 bytes per UUID
let contactCount = UInt(e164sToLookup.count)
guard plaintext.count == contactCount * 16 else {
throw ContactDiscoveryError.assertionError(description: "failed check: invalid byte count")
}
let dataParser = OWSDataParser(data: plaintext)
let uuidsData = try dataParser.nextData(length: contactCount * 16, name: "uuids")
guard dataParser.isEmpty else {
throw ContactDiscoveryError.assertionError(description: "failed check: dataParse.isEmpty")
}
let uuids = type(of: self).uuidArray(from: uuidsData)
guard uuids.count == contactCount else {
throw ContactDiscoveryError.assertionError(description: "failed check: uuids.count == contactCount")
}
let unregisteredUuid = UUID(uuid: (0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0))
var registeredContacts: Set<CDSRegisteredContact> = Set()
for (index, e164PhoneNumber) in e164sToLookup.enumerated() {
let uuid = uuids[index]
guard uuid != unregisteredUuid else {
Logger.verbose("not a signal user: \(e164PhoneNumber)")
continue
}
Logger.verbose("Signal user. e164: \(e164PhoneNumber), uuid: \(uuid)")
registeredContacts.insert(CDSRegisteredContact(signalUuid: uuid, e164PhoneNumber: e164PhoneNumber))
}
return registeredContacts
}
}
func buildIntersectionQuery(e164sToLookup: [E164], remoteAttestations: [RemoteAttestation.CDSAttestation.Id: RemoteAttestation]) throws -> ContactDiscoveryService.IntersectionQuery {
let noncePlainTextData = Randomness.generateRandomBytes(32)
let addressPlainTextData = ContactDiscoveryE164Collection(e164sToLookup).encodedValues
let queryData = Data.join([noncePlainTextData, addressPlainTextData])
let key = OWSAES256Key.generateRandom()
let encryptionResult = try Aes256GcmEncryptedData.encrypt(queryData, key: key.keyData)
assert(encryptionResult.ciphertext.count == e164sToLookup.count * 8 + 32)
let queryEnvelopes: [RemoteAttestation.CDSAttestation.Id: ContactDiscoveryService.IntersectionQuery.EnclaveEnvelope] = try remoteAttestations.mapValues { remoteAttestation in
let perEnclaveKey = try Aes256GcmEncryptedData.encrypt(
key.keyData,
key: remoteAttestation.keys.clientKey.keyData,
associatedData: remoteAttestation.requestId
)
return ContactDiscoveryService.IntersectionQuery.EnclaveEnvelope(
requestId: remoteAttestation.requestId,
data: perEnclaveKey.ciphertext,
iv: perEnclaveKey.nonce,
mac: perEnclaveKey.authenticationTag
)
}
guard let commitment = Cryptography.computeSHA256Digest(queryData) else {
throw ContactDiscoveryError.assertionError(description: "commitment was unexpectedly nil")
}
return ContactDiscoveryService.IntersectionQuery(
addressCount: UInt(e164sToLookup.count),
commitment: commitment,
data: encryptionResult.ciphertext,
iv: encryptionResult.nonce,
mac: encryptionResult.authenticationTag,
envelopes: queryEnvelopes
)
}
class func uuidArray(from data: Data) -> [UUID] {
return data.withUnsafeBytes {
[uuid_t]($0.bindMemory(to: uuid_t.self))
.map { UUID(uuid: $0) }
}
}
/// Parse the error and, if appropriate, construct an error appropriate to return upwards
/// May return the provided error unchanged.
class func prepareExternalError(from error: Error) -> Error {
// Network connectivity failures should never be re-wrapped
if error.isNetworkConnectivityFailure {
return error
}
let retryAfterDate = error.httpRetryAfterDate.map { min($0, Date(timeIntervalSinceNow: 60 * kMinuteInterval)) }
if let statusCode = error.httpStatusCode {
switch statusCode {
case 401:
return ContactDiscoveryError(
kind: .unauthorized,
debugDescription: "User is unauthorized",
retryable: false,
retryAfterDate: retryAfterDate)
case 404:
return ContactDiscoveryError(
kind: .unexpectedResponse,
debugDescription: "Unknown enclaveID",
retryable: false,
retryAfterDate: retryAfterDate)
case 408:
return ContactDiscoveryError(
kind: .timeout,
debugDescription: "Server rejected due to a timeout",
retryable: true,
retryAfterDate: retryAfterDate)
case 409:
// Conflict on a discovery request indicates that the requestId specified by the client
// has been dropped due to a delay or high request rate since the preceding corresponding
// attestation request. The client should not retry the request automatically
return ContactDiscoveryError(
kind: .genericClientError,
debugDescription: "RequestID conflict",
retryable: false,
retryAfterDate: retryAfterDate)
case 429:
return ContactDiscoveryError(
kind: .rateLimit,
debugDescription: "Rate limit",
retryable: true,
retryAfterDate: retryAfterDate)
case 400..<500:
return ContactDiscoveryError(
kind: .genericClientError,
debugDescription: "Client error (\(statusCode)): \(error.userErrorDescription)",
retryable: false,
retryAfterDate: retryAfterDate)
case 500..<600:
return ContactDiscoveryError(
kind: .genericServerError,
debugDescription: "Server error (\(statusCode)): \(error.userErrorDescription)",
retryable: true,
retryAfterDate: retryAfterDate)
default:
return ContactDiscoveryError(
kind: .generic,
debugDescription: "Unknown error (\(statusCode)): \(error.userErrorDescription)",
retryable: false,
retryAfterDate: retryAfterDate)
}
} else {
return error
}
}
}

View File

@ -1,122 +0,0 @@
//
// Copyright 2019 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only
//
import Foundation
public struct ContactDiscoveryService: Dependencies {
public struct IntersectionQuery: Codable {
public let addressCount: UInt
public let commitment: Data
public let data: Data
public let iv: Data
public let mac: Data
public struct EnclaveEnvelope: Codable {
public let requestId: Data
public let data: Data
public let iv: Data
public let mac: Data
}
public let envelopes: [RemoteAttestation.CDSAttestation.Id: EnclaveEnvelope]
}
public struct IntersectionResponse {
let requestId: Data
let data: Data
let iv: Data
let mac: Data
}
// MARK: -
public func getRegisteredSignalUsers(query: ContactDiscoveryService.IntersectionQuery,
cookies: [HTTPCookie],
authUsername: String,
authPassword: String,
enclaveName: String,
host: String,
censorshipCircumventionPrefix: String) -> Promise<IntersectionResponse> {
owsAssertDebug(authUsername.strippedOrNil != nil)
owsAssertDebug(authPassword.strippedOrNil != nil)
owsAssertDebug(enclaveName.strippedOrNil != nil)
owsAssertDebug(host.strippedOrNil != nil)
return firstly(on: DispatchQueue.sharedUtility) { () -> Promise<HTTPResponse> in
let urlSession = Self.signalService.urlSessionForCds(host: host,
censorshipCircumventionPrefix: censorshipCircumventionPrefix)
let request = self.buildIntersectionRequest(
query: query,
cookies: cookies,
authUsername: authUsername,
authPassword: authPassword,
enclaveName: enclaveName
)
guard let requestUrl = request.url else {
owsFailDebug("Missing requestUrl.")
throw OWSHTTPError.missingRequest
}
return firstly {
urlSession.promiseForTSRequest(request)
}.recover(on: DispatchQueue.global()) { error -> Promise<HTTPResponse> in
// OWSUrlSession should only throw OWSHTTPError or OWSAssertionError.
if let httpError = error as? OWSHTTPError {
throw httpError
} else {
owsFailDebug("Unexpected error: \(error)")
throw OWSHTTPError.invalidRequest(requestUrl: requestUrl)
}
}
}.map(on: DispatchQueue.sharedUtility) { (response: HTTPResponse) throws -> IntersectionResponse in
guard let json = response.responseBodyJson else {
throw OWSAssertionError("Invalid JSON")
}
guard let params = ParamParser(responseObject: json) else {
throw ContactDiscoveryError.assertionError(description: "missing response dict")
}
return IntersectionResponse(
requestId: try params.requiredBase64EncodedData(key: "requestId"),
data: try params.requiredBase64EncodedData(key: "data"),
iv: try params.requiredBase64EncodedData(key: "iv", byteCount: 12),
mac: try params.requiredBase64EncodedData(key: "mac", byteCount: 16))
}
}
// MARK: -
private func buildIntersectionRequest(query: IntersectionQuery,
cookies: [HTTPCookie],
authUsername: String,
authPassword: String,
enclaveName: String) -> TSRequest {
let path = "v1/discovery/\(enclaveName)"
let parameters: [String: Any] = [
"addressCount": query.addressCount,
"commitment": query.commitment.base64EncodedString(),
"data": query.data.base64EncodedString(),
"iv": query.iv.base64EncodedString(),
"mac": query.mac.base64EncodedString(),
"envelopes": query.envelopes.mapValues {
[
"requestId": $0.requestId.base64EncodedString(),
"data": $0.data.base64EncodedString(),
"iv": $0.iv.base64EncodedString(),
"mac": $0.mac.base64EncodedString()
]
}
]
let request = TSRequest(url: URL(string: path)!, method: "PUT", parameters: parameters)
request.authUsername = authUsername
request.authPassword = authPassword
// Set the cookie header.
// OWSURLSession disables default cookie handling for all requests.
assert(request.allHTTPHeaderFields?.count == 0)
request.allHTTPHeaderFields = HTTPCookie.requestHeaderFields(with: cookies)
return request
}
}

View File

@ -278,8 +278,6 @@ fileprivate extension HTTPUtils {
return httpError.isNetworkConnectivityError
case GroupsV2Error.timeout:
return true
case let contactDiscoveryError as ContactDiscoveryError:
return contactDiscoveryError.kind == .timeout
case PaymentsError.timeout:
return true
default:

View File

@ -135,7 +135,6 @@ typedef NS_ENUM(uint8_t, OWSIdentity);
#pragma mark - Remote Attestation
+ (TSRequest *)remoteAttestationAuthRequestForKeyBackup;
+ (TSRequest *)remoteAttestationAuthRequestForContactDiscovery;
+ (TSRequest *)remoteAttestationAuthRequestForCDSI;
#pragma mark - KBS

View File

@ -594,11 +594,6 @@ static NSString *_Nullable queryParamForIdentity(OWSIdentity identity)
return [TSRequest requestWithUrl:[NSURL URLWithString:@"v1/backup/auth"] method:@"GET" parameters:@{}];
}
+ (TSRequest *)remoteAttestationAuthRequestForContactDiscovery
{
return [TSRequest requestWithUrl:[NSURL URLWithString:@"v1/directory/auth"] method:@"GET" parameters:@{}];
}
+ (TSRequest *)remoteAttestationAuthRequestForCDSI
{
return [TSRequest requestWithUrl:[NSURL URLWithString:@"v2/directory/auth"] method:@"GET" parameters:@{}];

View File

@ -60,7 +60,6 @@ public enum SignalServiceType {
case storageService
case cdn0
case cdn2
case cds(host: String, censorshipCircumventionPrefix: String)
case remoteAttestation(host: String, censorshipCircumventionPrefix: String)
case kbs
case updates
@ -104,18 +103,6 @@ public extension OWSSignalServiceProtocol {
buildUrlSession(for: SignalServiceType.type(forCdnNumber: cdnNumber))
}
func urlSessionForCds(
host: String,
censorshipCircumventionPrefix: String
) -> OWSURLSessionProtocol {
buildUrlSession(
for: .cds(
host: host,
censorshipCircumventionPrefix: censorshipCircumventionPrefix
)
)
}
func urlSessionForRemoteAttestation(
host: String,
censorshipCircumventionPrefix: String
@ -189,13 +176,6 @@ extension SignalServiceType {
shouldUseSignalCertificate: true,
shouldHandleRemoteDeprecation: false
)
case .cds(let host, let censorshipCircumventionPrefix):
return SignalServiceInfo(
baseUrl: URL(string: host)!,
censorshipCircumventionPathPrefix: censorshipCircumventionPrefix,
shouldUseSignalCertificate: true,
shouldHandleRemoteDeprecation: false
)
case .remoteAttestation(let host, let censorshipCircumventionPrefix):
return SignalServiceInfo(
baseUrl: URL(string: host)!,

View File

@ -68,60 +68,6 @@ public extension RemoteAttestation {
}
}
// MARK: - CDS
public extension RemoteAttestation {
struct CDSAttestation {
/// An opaque, server-specified identifier to link an attestation to its corresponding envelope
public typealias Id = String
let cookies: [HTTPCookie]
let auth: Auth
let enclaveConfig: EnclaveConfig
let remoteAttestations: [Id: RemoteAttestation]
}
static func performForCDS() -> Promise<CDSAttestation> {
return performAttestation(
for: .contactDiscovery,
config: EnclaveConfig(
enclaveName: TSConstants.contactDiscoveryEnclaveName,
mrenclave: TSConstants.contactDiscoveryMrEnclave,
host: TSConstants.contactDiscoverySGXURL,
censorshipCircumventionPrefix: TSConstants.contactDiscoveryCensorshipPrefix
)
).map { attestationResponse -> CDSAttestation in
let attestationBody: [CDSAttestation.Id: [String: Any]] = try attestationResponse.responseBody.required(key: "attestations")
// The client MUST reject server responses with more than 3 Remote Attestation Responses attached,
// for security reasons.
guard (1..<4).contains(attestationBody.count) else {
throw ParamParser.ParseError.invalidFormat("attestations", description: "invalid attestation count: \(attestationBody.count)")
}
let attestations: [CDSAttestation.Id: RemoteAttestation] = try attestationBody.mapValues { attestationParams in
let parser = ParamParser(dictionary: attestationParams)
return try parseAttestationResponse(params: parser,
clientEphemeralKeyPair: attestationResponse.clientEphemeralKeyPair,
cookies: attestationResponse.cookies,
enclaveName: attestationResponse.enclaveConfig.enclaveName,
mrenclave: attestationResponse.enclaveConfig.mrenclave,
auth: attestationResponse.auth)
}
let attestation = CDSAttestation(cookies: attestationResponse.cookies,
auth: attestationResponse.auth,
enclaveConfig: attestationResponse.enclaveConfig,
remoteAttestations: attestations)
owsAssertDebug(attestation.auth.username.strippedOrNil != nil)
owsAssertDebug(attestation.auth.password.strippedOrNil != nil)
owsAssertDebug(attestation.enclaveConfig.enclaveName.strippedOrNil != nil)
owsAssertDebug(attestation.enclaveConfig.host.strippedOrNil != nil)
return attestation
}
}
}
// MARK: - CSDI
extension RemoteAttestation {
@ -302,13 +248,11 @@ public extension RemoteAttestation {
fileprivate extension RemoteAttestation {
enum Service {
case contactDiscovery
case keyBackup
case cdsi
func authRequest() -> TSRequest {
switch self {
case .contactDiscovery: return OWSRequestFactory.remoteAttestationAuthRequestForContactDiscovery()
case .keyBackup: return OWSRequestFactory.remoteAttestationAuthRequestForKeyBackup()
case .cdsi: return OWSRequestFactory.remoteAttestationAuthRequestForCDSI()
}
@ -397,11 +341,6 @@ fileprivate extension RemoteAttestation {
"clientPublic": clientEphemeralKeyPair.publicKey.base64EncodedString()
]
// When making requests to CDS, we need to tell the service to use IASv4
if case .contactDiscovery = service {
parameters["iasVersion"] = 4
}
let request = TSRequest(url: URL(string: path)!,
method: "PUT",
parameters: parameters)

View File

@ -47,8 +47,6 @@ public class TSConstants: NSObject {
@objc
public static var textSecureCDN2ServerURL: String { shared.textSecureCDN2ServerURL }
@objc
public static var contactDiscoverySGXURL: String { shared.contactDiscoverySGXURL }
@objc
public static var contactDiscoveryV2URL: String { shared.contactDiscoveryV2URL }
@objc
public static var keyBackupURL: String { shared.keyBackupURL }
@ -75,14 +73,10 @@ public class TSConstants: NSObject {
public static var serviceCensorshipPrefix: String { shared.serviceCensorshipPrefix }
public static var cdn0CensorshipPrefix: String { shared.cdn0CensorshipPrefix }
public static var cdn2CensorshipPrefix: String { shared.cdn2CensorshipPrefix }
public static var contactDiscoveryCensorshipPrefix: String { shared.contactDiscoveryCensorshipPrefix }
public static var keyBackupCensorshipPrefix: String { shared.keyBackupCensorshipPrefix }
public static var storageServiceCensorshipPrefix: String { shared.storageServiceCensorshipPrefix }
public static var contactDiscoveryV2CensorshipPrefix: String { shared.contactDiscoveryV2CensorshipPrefix }
@objc
public static var contactDiscoveryEnclaveName: String { shared.contactDiscoveryMrEnclave.stringValue }
public static var contactDiscoveryMrEnclave: MrEnclave { shared.contactDiscoveryMrEnclave }
static var contactDiscoveryV2MrEnclave: MrEnclave { shared.contactDiscoveryV2MrEnclave }
static var keyBackupEnclave: KeyBackupEnclave { shared.keyBackupEnclave }
@ -111,7 +105,6 @@ public protocol TSConstantsProtocol: AnyObject {
var mainServiceUnidentifiedURL: String { get }
var textSecureCDN0ServerURL: String { get }
var textSecureCDN2ServerURL: String { get }
var contactDiscoverySGXURL: String { get }
var contactDiscoveryV2URL: String { get }
var keyBackupURL: String { get }
var storageServiceURL: String { get }
@ -128,13 +121,10 @@ public protocol TSConstantsProtocol: AnyObject {
var serviceCensorshipPrefix: String { get }
var cdn0CensorshipPrefix: String { get }
var cdn2CensorshipPrefix: String { get }
var contactDiscoveryCensorshipPrefix: String { get }
var keyBackupCensorshipPrefix: String { get }
var storageServiceCensorshipPrefix: String { get }
var contactDiscoveryV2CensorshipPrefix: String { get }
// SGX Backed Contact Discovery
var contactDiscoveryMrEnclave: MrEnclave { get }
var contactDiscoveryV2MrEnclave: MrEnclave { get }
var keyBackupEnclave: KeyBackupEnclave { get }
@ -176,7 +166,6 @@ private class TSConstantsProduction: TSConstantsProtocol {
public let mainServiceUnidentifiedURL = "https://ud-chat.signal.org"
public let textSecureCDN0ServerURL = "https://cdn.signal.org"
public let textSecureCDN2ServerURL = "https://cdn2.signal.org"
public let contactDiscoverySGXURL = "https://api.directory.signal.org"
public let contactDiscoveryV2URL = "wss://cdsi.signal.org"
public let keyBackupURL = "https://api.backup.signal.org"
public let storageServiceURL = "https://storage.signal.org"
@ -193,12 +182,10 @@ private class TSConstantsProduction: TSConstantsProtocol {
public let serviceCensorshipPrefix = "service"
public let cdn0CensorshipPrefix = "cdn"
public let cdn2CensorshipPrefix = "cdn2"
public let contactDiscoveryCensorshipPrefix = "directory"
public let keyBackupCensorshipPrefix = "backup"
public let storageServiceCensorshipPrefix = "storage"
public let contactDiscoveryV2CensorshipPrefix = "cdsi"
public var contactDiscoveryMrEnclave = MrEnclave("74778bb0f93ae1f78c26e67152bab0bbeb693cd56d1bb9b4e9244157acc58081")
public let contactDiscoveryV2MrEnclave = MrEnclave("0f6fd79cdfdaa5b2e6337f534d3baf999318b0c462a7ac1f41297a3e4b424a57")
public let keyBackupEnclave = KeyBackupEnclave(
@ -230,7 +217,6 @@ private class TSConstantsStaging: TSConstantsProtocol {
public let mainServiceUnidentifiedURL = "https://ud-chat.staging.signal.org"
public let textSecureCDN0ServerURL = "https://cdn-staging.signal.org"
public let textSecureCDN2ServerURL = "https://cdn2-staging.signal.org"
public let contactDiscoverySGXURL = "https://api-staging.directory.signal.org"
public let contactDiscoveryV2URL = "wss://cdsi.staging.signal.org"
public let keyBackupURL = "https://api-staging.backup.signal.org"
public let storageServiceURL = "https://storage-staging.signal.org"
@ -249,13 +235,11 @@ private class TSConstantsStaging: TSConstantsProtocol {
public let serviceCensorshipPrefix = "service-staging"
public let cdn0CensorshipPrefix = "cdn-staging"
public let cdn2CensorshipPrefix = "cdn2-staging"
public let contactDiscoveryCensorshipPrefix = "directory-staging"
public let keyBackupCensorshipPrefix = "backup-staging"
public let storageServiceCensorshipPrefix = "storage-staging"
public let contactDiscoveryV2CensorshipPrefix = "cdsi-staging"
// CDS uses the same EnclaveName and MrEnclave
public var contactDiscoveryMrEnclave = MrEnclave("74778bb0f93ae1f78c26e67152bab0bbeb693cd56d1bb9b4e9244157acc58081")
public let contactDiscoveryV2MrEnclave = MrEnclave("0f6fd79cdfdaa5b2e6337f534d3baf999318b0c462a7ac1f41297a3e4b424a57")
public let keyBackupEnclave = KeyBackupEnclave(

View File

@ -241,10 +241,6 @@ public class RemoteConfig: BaseFlags {
getUIntValue(forFlag: .maxGroupCallRingSize, defaultValue: 16)
}
public static var contactDiscoveryV2KillSwitch: Bool {
isEnabled(.contactDiscoveryV2KillSwitch)
}
public static var enableAutoAPNSRotation: Bool {
return isEnabled(.enableAutoAPNSRotation, defaultValue: false)
}
@ -519,7 +515,6 @@ private struct Flags {
case paypalOneTimeDonationKillSwitch
case paypalGiftDonationKillSwitch
case paypalMonthlyDonationKillSwitch
case contactDiscoveryV2KillSwitch
case enableAutoAPNSRotation
case ringrtcNwPathMonitorTrialKillSwitch
}

View File

@ -0,0 +1,27 @@
//
// Copyright 2023 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only
//
import XCTest
@testable import SignalServiceKit
class ContactDiscoveryE164CollectionTest: XCTestCase {
func test_encodeNumber() throws {
let phoneNumbers = [try XCTUnwrap(E164("+1011"))]
let actual = ContactDiscoveryE164Collection(phoneNumbers).encodedValues
let expected: Data = Data([0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xf3])
XCTAssertEqual(expected, actual)
}
func test_encodeMultipleNumber() throws {
let phoneNumbers = [ try XCTUnwrap(E164("+1011")), try XCTUnwrap(E164("+19875550123")) ]
let actual = ContactDiscoveryE164Collection(phoneNumbers).encodedValues
let expected: Data = Data([
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xf3,
0x00, 0x00, 0x00, 0x04, 0xa0, 0xac, 0xd3, 0xab
])
XCTAssertEqual(expected, actual)
}
}

View File

@ -1,52 +0,0 @@
//
// Copyright 2018 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only
//
import XCTest
@testable import SignalServiceKit
class ContactDiscoveryOperationTest: XCTestCase {
func test_uuidArrayFromEmptyData() {
let data = Data()
let uuids = SGXContactDiscoveryOperation.uuidArray(from: data)
XCTAssertEqual([], uuids)
}
func test_uuidArrayFromZeroBytes() {
let data = Data(repeating: 0x00, count: 16)
let uuids = SGXContactDiscoveryOperation.uuidArray(from: data)
XCTAssertEqual([UUID(uuidString: "00000000-0000-0000-0000-000000000000")], uuids)
}
func test_uuidArrayFromBytes() {
let bytes: [UInt8] = [
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10
]
let data = Data(bytes)
let uuids = SGXContactDiscoveryOperation.uuidArray(from: data)
let expected = [UUID(uuidString: "00000000-0000-0000-0000-000000000000"),
UUID(uuidString: "00000000-0000-0000-0000-000000000000"),
UUID(uuidString: "01020304-0506-0708-090A-0B0C0D0E0F10")]
XCTAssertEqual(expected, uuids)
}
func test_encodeNumber() throws {
let phoneNumbers = [try XCTUnwrap(E164("+1011"))]
let actual = ContactDiscoveryE164Collection(phoneNumbers).encodedValues
let expected: Data = Data([0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xf3])
XCTAssertEqual(expected, actual)
}
func test_encodeMultipleNumber() throws {
let phoneNumbers = [ try XCTUnwrap(E164("+1011")), try XCTUnwrap(E164("+15551231234")) ]
let actual = ContactDiscoveryE164Collection(phoneNumbers).encodedValues
let expected: Data = Data([0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xf3,
0x00, 0x00, 0x00, 0x03, 0x9e, 0xec, 0xf5, 0x02])
XCTAssertEqual(expected, actual)
}
}